home *** CD-ROM | disk | FTP | other *** search
/ InterCD 2001 May / may_2001.iso / intercd / root / Multimedia / ^DivX_Article / virtualdub / VirtualDub-source-1_4d / Dub.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  2001-03-20  |  89.3 KB  |  3,201 lines

  1. //    VirtualDub - Video processing and capture application
  2. //    Copyright (C) 1998-2001 Avery Lee
  3. //
  4. //    This program is free software; you can redistribute it and/or modify
  5. //    it under the terms of the GNU General Public License as published by
  6. //    the Free Software Foundation; either version 2 of the License, or
  7. //    (at your option) any later version.
  8. //
  9. //    This program is distributed in the hope that it will be useful,
  10. //    but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. //    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  12. //    GNU General Public License for more details.
  13. //
  14. //    You should have received a copy of the GNU General Public License
  15. //    along with this program; if not, write to the Free Software
  16. //    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  17.  
  18. #define f_DUB_CPP
  19.  
  20. #include "VirtualDub.h"
  21.  
  22. #include <process.h>
  23. #include <crtdbg.h>
  24. #include <time.h>
  25. #include <stdio.h>
  26.  
  27. #include <windows.h>
  28. #include <commctrl.h>
  29. #include <vfw.h>
  30. #include <ddraw.h>
  31.  
  32. #include "resource.h"
  33.  
  34. #include "crash.h"
  35. #include "tls.h"
  36. #include "convert.h"
  37. #include "filters.h"
  38. #include "gui.h"
  39. #include "ddrawsup.h"
  40. #include "prefs.h"
  41. #include "command.h"
  42. #include "misc.h"
  43.  
  44. //#define new new(_NORMAL_BLOCK, __FILE__, __LINE__)
  45.  
  46. #include "Error.h"
  47. #include "VideoSequenceCompressor.h"
  48. #include "AsyncBlitter.h"
  49. #include "AVIOutputPreview.h"
  50. #include "AVIOutput.h"
  51. #include "Histogram.h"
  52. #include "AudioSource.h"
  53. #include "VideoSource.h"
  54. #include "AVIPipe.h"
  55. #include "VBitmap.h"
  56. #include "FrameSubset.h"
  57. #include "InputFile.h"
  58. #include "VideoTelecineRemover.h"
  59.  
  60. #include "dub.h"
  61. #include "dubstatus.h"
  62.  
  63. //////////////
  64.  
  65. #define ASYNCHRONOUS_OVERLAY_SUPPORT
  66.  
  67. //#define STOP_SPEED_DEBUGGING
  68.  
  69. //#define RELEASE_MODE_DEBUGGING
  70.  
  71. #ifdef RELEASE_MODE_DEBUGGING
  72. #define _XRPT0(y,x) OutputDebugString(x)
  73. #else
  74. #define _XRPT0(y,x) _RPT0(y,x)
  75. #endif
  76.  
  77. #define DEBUG_SLEEP
  78. //#define DEBUG_SLEEP Sleep(2000)
  79.  
  80. //////////////
  81.  
  82. #ifdef STOP_SPEED_DEBUGGING
  83.  
  84.     static __int64 start_time, stop_time;
  85.  
  86. #endif
  87.  
  88. DubOptions g_dubOpts = {
  89.     {
  90.         0,                // no amp
  91.         500,            // preload by 500ms
  92.         1,                // every frame
  93.         0,                // no new rate
  94.         0,                // offset: 0ms
  95.         false,            // period is in frames
  96.         true,            // audio interleaving enabled
  97.         true,            // yes, offset audio with video
  98.         true,            // yes, clip audio to video length
  99.         false,            // no integral change
  100.         false,            // no high quality
  101.         DubAudioOptions::P_NOCHANGE,        // no precision change
  102.         DubAudioOptions::C_NOCHANGE,        // no channel change
  103.         DubAudioOptions::M_NONE,
  104.     },
  105.  
  106.     {
  107.         DubVideoOptions::D_24BIT,    // input: 24bit
  108.         DubVideoOptions::D_24BIT,    // output: 24bit
  109.         DubVideoOptions::M_FULL,    // mode: full
  110.         TRUE,                        // show input video
  111.         TRUE,                        // show output video
  112.         FALSE,                        // decompress output video before display
  113.         FALSE,                        // histograms
  114.         TRUE,                        // sync to audio
  115.         1,                            // no frame rate decimation
  116.         0,                            // no change in frame rate
  117.         0,                            // start offset: 0ms
  118.         0,                            // end offset: 0ms
  119.         false,                        // No inverse telecine
  120.         false,                        // (IVTC mode)
  121.         -1,                            // (IVTC offset)
  122.         false,                        // (IVTC polarity)
  123.         0,                            // progressive preview
  124.     },
  125.  
  126.     {
  127.         1048576,                    // 1Mb AVI output buffer
  128.         65536,                    // 64K WAV input buffer
  129.         32,                        // 32 pipe buffers
  130.         true,                    // dynamic enable
  131.         false,
  132.         false,                    // directdraw,
  133.         true,                    // drop frames
  134.     },
  135.  
  136.     true,            // show status
  137.     false,            // move slider
  138. };
  139.  
  140. static const int g_iPriorities[][2]={
  141.  
  142.     // I/O                            processor
  143.     { THREAD_PRIORITY_IDLE,            THREAD_PRIORITY_IDLE,            },
  144.     { THREAD_PRIORITY_LOWEST,        THREAD_PRIORITY_LOWEST,            },
  145.     { THREAD_PRIORITY_BELOW_NORMAL,    THREAD_PRIORITY_LOWEST,            },
  146.     { THREAD_PRIORITY_NORMAL,        THREAD_PRIORITY_BELOW_NORMAL,    },
  147.     { THREAD_PRIORITY_NORMAL,        THREAD_PRIORITY_NORMAL,            },
  148.     { THREAD_PRIORITY_ABOVE_NORMAL,    THREAD_PRIORITY_NORMAL,            },
  149.     { THREAD_PRIORITY_HIGHEST,        THREAD_PRIORITY_ABOVE_NORMAL,    },
  150.     { THREAD_PRIORITY_HIGHEST,        THREAD_PRIORITY_HIGHEST,        }
  151. };
  152.  
  153. /////////////////////////////////////////////////
  154. void AVISTREAMINFOtoAVIStreamHeader(AVIStreamHeader_fixed *dest, AVISTREAMINFO *src) {
  155.     dest->fccType            = src->fccType;
  156.     dest->fccHandler        = src->fccHandler;
  157.     dest->dwFlags            = src->dwFlags;
  158.     dest->wPriority            = src->wPriority;
  159.     dest->wLanguage            = src->wLanguage;
  160.     dest->dwInitialFrames    = src->dwInitialFrames;
  161.     dest->dwStart            = src->dwStart;
  162.     dest->dwScale            = src->dwScale;
  163.     dest->dwRate            = src->dwRate;
  164.     dest->dwLength            = src->dwLength;
  165.     dest->dwSuggestedBufferSize = src->dwSuggestedBufferSize;
  166.     dest->dwQuality            = src->dwQuality;
  167.     dest->dwSampleSize        = src->dwSampleSize;
  168.     dest->rcFrame.left        = (short)src->rcFrame.left;
  169.     dest->rcFrame.top        = (short)src->rcFrame.top;
  170.     dest->rcFrame.right        = (short)src->rcFrame.right;
  171.     dest->rcFrame.bottom    = (short)src->rcFrame.bottom;
  172.  
  173.     _RPT3(0,"scale %ld, rate %ld, length %ld\n",src->dwScale,src->dwRate, src->dwLength);
  174. }
  175. /////////////////////////////////////////////////
  176.  
  177. extern const char g_szOutOfMemory[];
  178. extern const char g_szError[];
  179. extern BOOL g_syncroBlit, g_vertical;
  180. extern HWND g_hWnd;
  181. extern HINSTANCE g_hInst;
  182. extern bool g_fWine;
  183.  
  184. ///////////////////////////////////////////////////////////////////////////
  185.  
  186. class Dubber : public IDubber {
  187. private:
  188.     static void CALLBACK DubFrameTimerProc(UINT uID, UINT uMsg, DWORD dwUser, DWORD dw1, DWORD dw2);
  189.     static int PulseCallbackProc(void *_thisPtr, DWORD framenum);
  190.  
  191.     void ResizeInputBuffer(long bufsize);
  192.     void ResizeAudioBuffer(long bufsize);
  193.     void ReadVideoFrame(long lVStreamPos, BOOL preload);
  194.     void ReadNullVideoFrame(long lVStreamPos);
  195.     long ReadAudio(long& lAStreamPos, long samples);
  196.     void CheckSpill(long videopt, long audiopt);
  197.     void NextSegment();
  198.     void MainAddVideoFrame();
  199.     void MainAddAudioFrame(int);
  200.     static void MainThreadKickstart(void *thisPtr);
  201.     void MainThread();
  202.     void WriteVideoFrame(void *buffer, int exdata, LONG lastSize, long sample_num);
  203.     void WriteAudio(void *buffer, long lActualBytes, long lActualSamples);
  204.     static void ProcessingThreadKickstart(void *thisPtr);
  205.     void ProcessingThread();
  206.  
  207.     MyError                err;
  208.     bool                fError;
  209.     LONG                lStopCount;
  210.  
  211.     DubOptions            *opt;
  212.     AudioSource            *aSrc;
  213.     VideoSource            *vSrc;
  214.     InputFile            *pInput;
  215.     AVIOutput            *AVIout;
  216.     COMPVARS            *compVars;
  217.     HDC                    hDCWindow;
  218.  
  219.     DubAudioStreamInfo    aInfo;
  220.     DubVideoStreamInfo    vInfo;
  221.  
  222.     bool                fUseVideoCompression;
  223.     bool                fPreview;
  224.     volatile bool        fAbort;
  225.     volatile bool        fUserAbort;
  226.     bool                fADecompressionOk;
  227.     bool                fVDecompressionOk;
  228.     BOOL                fFiltersOk;
  229.     BOOL                fNoProcessingPriority;
  230.     UINT                timerInterval;
  231.     MMRESULT            timerID;
  232.  
  233.     HANDLE                hEventAbortOk;
  234.     volatile LONG        lThreadsActive;
  235.     HANDLE                hThreadMain;
  236.     HANDLE                hThreadProcessor;
  237.  
  238.     void *                inputBuffer;
  239.     long                inputBufferSize;
  240.     void *                audioBuffer;
  241.     long                audioBufferSize;
  242.  
  243.     VideoSequenceCompressor    *pVideoPacker;
  244.  
  245.     unsigned char *        frameBuffer;
  246.  
  247.     AVIPipe *            pipe;
  248.     AsyncBlitter *        blitter;
  249.  
  250.     HIC                    outputDecompressor;
  251.     HIC                    hicOutput;
  252.     HDRAWDIB            hDDInput, hDDOutput;
  253.     HDC                    hdcCompatInput, hdcCompatOutput;
  254.     HBITMAP                hbmInput, hbmOutput, hbmInputOld, hbmOutputOld;
  255.     BITMAPINFO            biInput, biOutput;
  256.     void                *lpvInput, *lpvOutput;
  257.  
  258.     int                    x_client, y_client;
  259.     RECT                rInputFrame, rOutputFrame, rInputHistogram, rOutputHistogram;
  260.     bool                fShowDecompressedFrame;
  261.     bool                fDisplay565;
  262.     IDDrawSurface        *pdsInput;
  263.     IDDrawSurface        *pdsOutput;
  264.  
  265.     int                    iOutputDepth;
  266.     BITMAPINFOHEADER    *decompressedVideoFormat;
  267.     BITMAPINFO            *compressorVideoFormat;
  268.     BITMAPINFO            compressorVideoDIBFormat;
  269.     BITMAPV4HEADER        bihDisplayFormat;
  270.  
  271.     AudioStream            *audioStreamSource;
  272.     AudioStream            *audioStreamConverter;
  273.     AudioStream            *audioStreamResampler;
  274.     AudioStream            *audioStreamAmplifier;
  275.     AudioStream            *audioSubsetFilter;
  276.     AudioStream            *audioStream, *audioTimingStream;
  277.     AudioStream            *audioStatusStream;
  278.     AudioL3Corrector    *audioCorrector;
  279.     AudioCompressor        *audioCompressor;
  280.  
  281.     FrameSubset                *inputSubsetActive;
  282.     FrameSubset                *inputSubsetAlloc;
  283.     VideoTelecineRemover    *pInvTelecine;
  284.     int                    nVideoLag;
  285.     int                    nVideoLagNoTelecine;
  286.     int                    nVideoLagPreload;
  287.  
  288.     WAVEFORMATEX        *wfexAudioCompressionFormat;
  289.     long                cbAudioCompressionFormat;
  290.  
  291.     Histogram            *inputHisto, *outputHisto;
  292.  
  293.     volatile int        okToDraw;
  294.     HWND                hwndStatus;
  295.  
  296.     DWORD                timer_counter, timer_period;
  297.     bool                fSyncToAudioEvenClock;
  298.     int                    iFrameDisplacement;
  299.  
  300.     int                    iPriority;
  301.     long                lDropFrames;
  302.  
  303.     FilterStateInfo        fsi;
  304.  
  305.     bool                fPhantom;
  306.  
  307.     IDubStatusHandler    *pStatusHandler;
  308.  
  309.     __int64                i64SegmentSize;
  310.     volatile __int64    i64SegmentCredit;
  311.     __int64                i64SegmentThreshold;
  312.     long                lVideoSizeEstimate;
  313.     const char *        pszSegmentPrefix;
  314.     bool                fEnableSpill;
  315.     int                    nSpillSegment;
  316.     long                lSpillVideoPoint, lSpillAudioPoint;
  317.     long                lSpillVideoOk, lSpillAudioOk;
  318.     long                lSegmentFrameLimit;
  319.     long                lSegmentFrameStart;
  320.  
  321.     ///////
  322.  
  323. public:
  324.     Dubber(DubOptions *);
  325.     ~Dubber();
  326.  
  327.     void SetAudioCompression(WAVEFORMATEX *wf, LONG cb);
  328.     void SetPhantomVideoMode();
  329.     void SetInputFile(InputFile *pInput);
  330.     void SetFrameRectangles(RECT *prInput, RECT *prOutput);
  331.     void SetClientRectOffset(int x, int y);
  332.     void EnableSpill(const char *pszPrefix, __int64 threshold, long framethreshold);
  333.  
  334.     static void Dubber::SetClientRectOffset2(void *pv);
  335.     static void Dubber::SetFrameRectangles2(void *pv);
  336.  
  337.  
  338.     void InitAudioConversionChain();
  339.     void InitOutputFile(char *pszFile);
  340.     bool AttemptInputOverlay(BITMAPINFOHEADER *pbih);
  341.     void AttemptInputOverlays();
  342.     static void AttemptInputOverlays2(void *pThis);
  343.  
  344.     bool AttemptOutputOverlay();
  345.     void InitDirectDraw();
  346.     void InitDisplay();
  347.     bool NegotiateFastFormat(BITMAPINFOHEADER *pbih);
  348.     bool NegotiateFastFormat(int depth);
  349.     void InitSelectInputFormat();
  350.     void Init(VideoSource *video, AudioSource *audio, AVIOutput *out, char *szFile, HDC hDC, COMPVARS *videoCompVars);
  351.     void Go(int iPriority = 0);
  352.     void Stop();
  353.  
  354.     void RealizePalette();
  355.     void Abort();
  356.     void ForceAbort();
  357.     bool isAbortedByUser();
  358.     void Tag(int x, int y);
  359.  
  360.     void SetStatusHandler(IDubStatusHandler *pdsh);
  361.     void SetPriority(int index);
  362.     void UpdateFrames();
  363. };
  364.  
  365.  
  366. ///////////////////////////////////////////////////////////////////////////
  367.  
  368. IDubber::~IDubber() {
  369. }
  370.  
  371. IDubber *CreateDubber(DubOptions *xopt) {
  372.     return new Dubber(xopt);
  373. }
  374.  
  375. Dubber::Dubber(DubOptions *xopt) {
  376.     opt                = xopt;
  377.     aSrc            = NULL;
  378.     vSrc            = NULL;
  379.     pInput            = NULL;
  380.  
  381.     // clear the workin' variables...
  382.  
  383.     fError                = false;
  384.     lStopCount            = 0;
  385.  
  386.     fAbort                = false;
  387.     fUserAbort            = false;
  388.  
  389.     pVideoPacker        = NULL;
  390.     pStatusHandler        = NULL;
  391.  
  392.     fADecompressionOk    = false;
  393.     fVDecompressionOk    = false;
  394.     fFiltersOk            = FALSE;
  395.     timerInterval        = 0;
  396.     timerID                = NULL;
  397.  
  398.     hEventAbortOk        = INVALID_HANDLE_VALUE;
  399.     lThreadsActive        = 0;
  400.     hThreadMain            = NULL;
  401.     hThreadProcessor    = NULL;
  402.     inputBuffer            = NULL;
  403.     audioBuffer            = NULL;
  404.     inputBufferSize        = 0;
  405.     audioBufferSize        = 0;
  406. //    hFileShared            = INVALID_HANDLE_VALUE;
  407. //    tempBuffer            = NULL;
  408. //    outputBuffer        = NULL;
  409.     pipe                = NULL;
  410.     blitter                = NULL;
  411.     outputDecompressor    = NULL;
  412.     hDDInput            = NULL;
  413.     hDDOutput            = NULL;
  414.     okToDraw            = 0;
  415.     hwndStatus            = NULL;
  416.     vInfo.total_size    = 0;
  417.     aInfo.total_size    = 0;
  418.     vInfo.fAudioOnly    = false;
  419.  
  420.     hdcCompatInput = hdcCompatOutput = NULL;
  421.     hbmInput = hbmOutput = NULL;
  422.     pdsInput            = NULL;
  423.     pdsOutput            = NULL;
  424.  
  425.     audioStreamSource        = NULL;
  426.     audioStreamConverter    = NULL;
  427.     audioStreamResampler    = NULL;
  428.     audioStreamAmplifier    = NULL;
  429.     audioStatusStream        = NULL;
  430.     audioSubsetFilter        = NULL;
  431.     audioCompressor            = NULL;
  432.     audioCorrector            = NULL;
  433.  
  434.     inputSubsetActive        = NULL;
  435.     inputSubsetAlloc        = NULL;
  436.  
  437.     wfexAudioCompressionFormat = NULL;
  438.  
  439.     inputHisto            = NULL;
  440.     outputHisto            = NULL;
  441.  
  442.     iFrameDisplacement    = 0;
  443.  
  444.     fPhantom = false;
  445.  
  446.     pInvTelecine        = NULL;
  447.  
  448.     i64SegmentSize        = 0;
  449.     i64SegmentCredit    = 0;
  450.     AVIout                = NULL;
  451.     fEnableSpill        = false;
  452.  
  453.     lSpillVideoPoint    = 0;
  454.     lSpillAudioPoint    = 0;
  455.     lSegmentFrameLimit    = 0;
  456.     lSegmentFrameStart    = 0;
  457.  
  458.     hicOutput = NULL;
  459. }
  460.  
  461. Dubber::~Dubber() {
  462.     _RPT0(0,"Dubber: destructor called.\n");
  463.  
  464.     Stop();
  465. }
  466.  
  467. /////////////////////////////////////////////////
  468.  
  469. void Dubber::SetAudioCompression(WAVEFORMATEX *wf, LONG cb) {
  470.     wfexAudioCompressionFormat = wf;
  471.     cbAudioCompressionFormat = cb;
  472. }
  473.  
  474. void Dubber::SetPhantomVideoMode() {
  475.     fPhantom = true;
  476.     vInfo.fAudioOnly = true;
  477. }
  478.  
  479. void Dubber::SetInputFile(InputFile *pInput) {
  480.     this->pInput = pInput;
  481. }
  482.  
  483. void Dubber::SetStatusHandler(IDubStatusHandler *pdsh) {
  484.     pStatusHandler = pdsh;
  485. }
  486.  
  487.  
  488. /////////////
  489.  
  490. struct DubberSetFrameRectangles {
  491.     IDDrawSurface *pDD;
  492.     RECT *pr;
  493.  
  494.     DubberSetFrameRectangles(IDDrawSurface *_pDD, RECT *_pr) : pDD(_pDD), pr(_pr) {}
  495. };
  496.  
  497. void Dubber::SetFrameRectangles2(void *pv) {
  498.     DubberSetFrameRectangles *pData = (DubberSetFrameRectangles *)pv;
  499.  
  500.     pData->pDD->SetOverlayPos(pData->pr);
  501. }
  502.  
  503. void Dubber::SetFrameRectangles(RECT *prInput, RECT *prOutput) {
  504.     rInputFrame = *prInput;
  505.     rOutputFrame = *prOutput;
  506.  
  507.     if (g_vertical) {
  508.         rInputHistogram.left    = rInputFrame.right + 6;
  509.         rInputHistogram.top        = rInputFrame.top;
  510.         rOutputHistogram.left    = rOutputFrame.right + 6;
  511.         rOutputHistogram.top    = rOutputFrame.top;
  512.     } else {
  513.         rInputHistogram.left    = rInputFrame.left;
  514.         rInputHistogram.top        = rInputFrame.bottom + 6;
  515.         rOutputHistogram.left    = rOutputFrame.left;
  516.         rOutputHistogram.top    = rOutputFrame.bottom + 6;
  517.     }
  518.  
  519.     rInputHistogram.right    = rInputHistogram.left + 256;
  520.     rInputHistogram.bottom    = rInputHistogram.top  + 128;
  521.  
  522.     rOutputHistogram.right    = rOutputHistogram.left + 256;
  523.     rOutputHistogram.bottom    = rOutputHistogram.top  + 128;
  524.  
  525.     if (pdsInput) {
  526.         RECT r = rInputFrame;
  527.  
  528.         r.left += x_client;
  529.         r.right += x_client;
  530.         r.top += y_client;
  531.         r.bottom += y_client;
  532.  
  533. #ifdef ASYNCHRONOUS_OVERLAY_SUPPORT
  534.         blitter->postAFC(0x80000000, SetFrameRectangles2, &DubberSetFrameRectangles(pdsInput, &r));
  535. #else
  536.         pdsInput->SetOverlayPos(&r);
  537. #endif
  538.     }
  539. }
  540.  
  541. /////////////
  542.  
  543. struct DubberSetClientRectOffset {
  544.     IDDrawSurface *pDD;
  545.     long x,y;
  546.  
  547.     DubberSetClientRectOffset(IDDrawSurface *_pDD, long _x, long _y) : pDD(_pDD), x(_x), y(_y) {}
  548. };
  549.  
  550.  
  551. void Dubber::SetClientRectOffset2(void *pv) {
  552.     DubberSetClientRectOffset *pData = (DubberSetClientRectOffset *)pv;
  553.  
  554.     pData->pDD->MoveOverlay(pData->x, pData->y);
  555. }
  556.  
  557. void Dubber::SetClientRectOffset(int x, int y) {
  558.     x_client = x;
  559.     y_client = y;
  560.  
  561.     if (pdsInput)
  562. #ifdef ASYNCHRONOUS_OVERLAY_SUPPORT
  563.         blitter->postAFC(0x80000000, SetClientRectOffset2, &DubberSetClientRectOffset(pdsInput, x + rInputFrame.left, y + rInputFrame.top));
  564. #else
  565.         pdsInput->MoveOverlay(x + rInputFrame.left, y + rInputFrame.top);
  566. #endif
  567. }
  568.  
  569. void Dubber::EnableSpill(const char *pszPrefix, __int64 segsize, long framecnt) {
  570.     pszSegmentPrefix = pszPrefix;
  571.     fEnableSpill = true;
  572.     nSpillSegment = 1;
  573.     i64SegmentThreshold = segsize;
  574.     lSegmentFrameLimit = framecnt;
  575. }
  576.  
  577. void InitStreamValuesStatic(DubVideoStreamInfo& vInfo, DubAudioStreamInfo& aInfo, VideoSource *video, AudioSource *audio, DubOptions *opt, FrameSubset *pfs) {
  578.     if (!pfs)
  579.         pfs = inputSubset;
  580.  
  581.     if (video) {
  582.  
  583.         if (pfs) {
  584.             vInfo.start_src        = 0;
  585.             vInfo.end_src        = pfs->getTotalFrames();
  586.         } else {
  587.             vInfo.start_src        = video->lSampleFirst;
  588.             vInfo.end_src        = video->lSampleLast;
  589.         }
  590.     } else {
  591.         vInfo.start_src        = vInfo.start_dst    = 0;
  592.         vInfo.end_src        = vInfo.end_dst        = 0;
  593.     }
  594.  
  595.     if (audio) {
  596.         aInfo.start_src        = audio->lSampleFirst;
  597.         aInfo.end_src        = audio->lSampleLast;
  598.     } else {
  599.         aInfo.start_src        = aInfo.start_dst    = 0;
  600.         aInfo.end_src        = aInfo.end_dst        = 0;
  601.     }
  602.  
  603.     vInfo.cur_src            = vInfo.start_src;
  604.     aInfo.cur_src            = aInfo.start_src;
  605.  
  606.     if (video) {
  607.         // compute new frame rate
  608.  
  609.         vInfo.usPerFrame    = MulDiv(video->streamInfo.dwScale,1000000,video->streamInfo.dwRate);
  610.  
  611.         if (opt->video.frameRateNewMicroSecs == DubVideoOptions::FR_SAMELENGTH) {
  612.             if (audio && audio->streamInfo.dwLength)
  613.                 vInfo.usPerFrame    = MulDiv(audio->samplesToMs(audio->streamInfo.dwLength),1000,video->streamInfo.dwLength);
  614.         } else if (opt->video.frameRateNewMicroSecs)
  615.             vInfo.usPerFrame    = opt->video.frameRateNewMicroSecs;
  616.  
  617.         // are we supposed to offset the video?
  618.  
  619.         if (opt->video.lStartOffsetMS) {
  620.             vInfo.start_src += video->msToSamples(opt->video.lStartOffsetMS); 
  621.         }
  622.  
  623.         if (opt->video.lEndOffsetMS)
  624.             vInfo.end_src -= video->msToSamples(opt->video.lEndOffsetMS);
  625.  
  626.         vInfo.usPerFrameIn    = vInfo.usPerFrame;
  627.         vInfo.usPerFrame    *= opt->video.frameRateDecimation;
  628.  
  629.         // make sure we start reading on a key frame
  630.  
  631.         if (opt->video.mode == DubVideoOptions::M_NONE)
  632.             vInfo.start_src    = video->nearestKey(vInfo.start_src);
  633.  
  634.         vInfo.cur_src        = vInfo.start_src;
  635.         vInfo.cur_dst        = vInfo.start_dst;
  636.     }
  637.  
  638.     if (audio) {
  639.         long lStartOffsetMS = -opt->audio.offset;
  640.  
  641.         // offset the start of the audio appropriately...
  642.  
  643.         if (opt->audio.fStartAudio && video && opt->video.lStartOffsetMS) {
  644.             if (!pfs)
  645.                 lStartOffsetMS += MulDiv(vInfo.usPerFrame, vInfo.start_src - video->lSampleFirst, 1000*opt->video.frameRateDecimation);
  646.         }
  647.  
  648.         aInfo.start_src += audio->msToSamples(lStartOffsetMS);
  649.  
  650.         // clip the end of the audio if supposed to...
  651.  
  652.         if (opt->audio.fEndAudio) {
  653.             long lMaxLength;
  654.  
  655.             lMaxLength = (long)((
  656.                             (
  657.                                 (__int64)(vInfo.end_src - vInfo.start_src)
  658.                                 *
  659.                                 audio->streamInfo.dwRate
  660.                             )
  661.                             * vInfo.usPerFrame
  662.                         ) / ((__int64)audio->streamInfo.dwScale * 1000000 * opt->video.frameRateDecimation));
  663.  
  664.             if (aInfo.end_src - aInfo.start_src > lMaxLength)
  665.                 aInfo.end_src = aInfo.start_src + lMaxLength;
  666.         }
  667.  
  668.         // resampling audio?
  669.  
  670.         aInfo.resampling = false;
  671.         aInfo.converting = false;
  672.  
  673.         if (opt->audio.mode > DubAudioOptions::M_NONE) {
  674.             if (opt->audio.new_rate) {
  675.                 aInfo.resampling = true;
  676.             }
  677.  
  678.             if (opt->audio.newPrecision != DubAudioOptions::P_NOCHANGE || opt->audio.newChannels != DubAudioOptions::C_NOCHANGE) {
  679.                 aInfo.converting = true;
  680.  
  681.                 aInfo.is_16bit = opt->audio.newPrecision==DubAudioOptions::P_16BIT
  682.                                 || (opt->audio.newPrecision==DubAudioOptions::P_NOCHANGE && audio->getWaveFormat()->wBitsPerSample>8);
  683.                 aInfo.is_stereo = opt->audio.newChannels==DubAudioOptions::C_STEREO
  684.                                 || (opt->audio.newChannels==DubAudioOptions::C_NOCHANGE && audio->getWaveFormat()->nChannels>1);
  685.                 aInfo.is_right = (opt->audio.newChannels==DubAudioOptions::C_MONORIGHT);
  686.                 aInfo.single_channel = (opt->audio.newChannels==DubAudioOptions::C_MONOLEFT || opt->audio.newChannels==DubAudioOptions::C_MONORIGHT);
  687.                 aInfo.bytesPerSample = (aInfo.is_16bit ? 2 : 1) * (aInfo.is_stereo ? 2 : 1);
  688.  
  689.             }
  690.         }
  691.  
  692.         aInfo.cur_src        = audio->nearestKey(aInfo.start_src);
  693.         aInfo.cur_dst        = aInfo.start_dst;
  694.     }
  695.  
  696.     vInfo.cur_proc_src = vInfo.cur_src;
  697.     aInfo.cur_proc_src = aInfo.cur_src;
  698.  
  699.     _RPT3(0,"Dub: Audio is from (%ld,%ld) starting at %ld\n", aInfo.start_src, aInfo.end_src, aInfo.cur_src);
  700.     _RPT3(0,"Dub: Video is from (%ld,%ld) starting at %ld\n", vInfo.start_src, vInfo.end_src, vInfo.cur_src);
  701. }
  702.  
  703. //////////////////////////////////////////////////////////////////////////////
  704.  
  705. // may be called at any time in Init() after streams setup
  706.  
  707. void Dubber::InitAudioConversionChain() {
  708.  
  709.     // ready the audio stream for streaming operation
  710.  
  711.     aSrc->streamBegin(fPreview);
  712.     fADecompressionOk = true;
  713.  
  714.     // Initialize audio conversion chain
  715.     //
  716.     // First, create a source.
  717.  
  718.     if (!(audioStreamSource = new AudioStreamSource(aSrc, aInfo.start_src, aSrc->lSampleLast - aInfo.start_src, opt->audio.mode > DubAudioOptions::M_NONE)))
  719.         throw MyError("Dub: Unable to create audio stream source");
  720.  
  721.     audioStream = audioStreamSource;
  722.  
  723.     // Attach a converter if we need to...
  724.  
  725.     if (aInfo.converting) {
  726.         if (aInfo.single_channel)
  727.             audioStreamConverter = new AudioStreamConverter(audioStream, aInfo.is_16bit, aInfo.is_right, true);
  728.         else
  729.             audioStreamConverter = new AudioStreamConverter(audioStream, aInfo.is_16bit, aInfo.is_stereo, false);
  730.  
  731.         if (!audioStreamConverter)
  732.             throw MyError("Dub: Unable to create audio stream converter");
  733.  
  734.         audioStream = audioStreamConverter;
  735.     }
  736.  
  737.     // Attach a converter if we need to...
  738.  
  739.     if (aInfo.resampling) {
  740.         if (!(audioStreamResampler = new AudioStreamResampler(audioStream, opt->audio.new_rate ? opt->audio.new_rate : aSrc->getWaveFormat()->nSamplesPerSec, opt->audio.integral_rate, opt->audio.fHighQuality)))
  741.             throw MyError("Dub: Unable to create audio stream resampler");
  742.  
  743.         audioStream = audioStreamResampler;
  744.     }
  745.  
  746.     // Attach an amplifier if needed...
  747.  
  748.     if (opt->audio.mode > DubAudioOptions::M_NONE && opt->audio.volume) {
  749.         if (!(audioStreamAmplifier = new AudioStreamAmplifier(audioStream, opt->audio.volume)))
  750.             throw MyError("Dub: Unable to create audio stream amplifier");
  751.  
  752.         audioStream = audioStreamAmplifier;
  753.     }
  754.  
  755.     audioTimingStream = audioStream;
  756.  
  757.     // Tack on a subset filter as well...
  758.  
  759.     if (inputSubsetActive) {
  760.         if (!(audioSubsetFilter = new AudioSubset(audioStream, inputSubsetActive, vInfo.usPerFrameIn,
  761.                     opt->audio.fStartAudio ? MulDiv(vInfo.usPerFrameIn, vInfo.start_src, 1000) : 0
  762.                 )))
  763.             throw MyError("Dub: Unable to create audio subset filter");
  764.  
  765.         audioStream = audioSubsetFilter;
  766.     }
  767.  
  768.     // Make sure we only get what we want...
  769.  
  770.     if (vSrc && opt->audio.fEndAudio)
  771.         audioStream->SetLimit((long)((
  772.             ((__int64)(vInfo.end_src - vInfo.start_src) * audioStream->GetFormat()->nAvgBytesPerSec * (__int64)vInfo.usPerFrameIn)) / ((__int64)1000000 * audioStream->GetFormat()->nBlockAlign)
  773.             ));
  774.  
  775.     audioStatusStream = audioStream;
  776.  
  777.     // Tack on a compressor if we want...
  778.  
  779.     if (opt->audio.mode > DubAudioOptions::M_NONE && wfexAudioCompressionFormat) {
  780.         if (!(audioCompressor = new AudioCompressor(audioStream, wfexAudioCompressionFormat, cbAudioCompressionFormat)))
  781.             throw MyError("Dub: Unable to create audio compressor");
  782.  
  783.         audioStream = audioCompressor;
  784.     }
  785.  
  786.     // Check the output format, and if we're compressing to
  787.     // MPEG Layer III, compensate for the lag and create a bitrate corrector
  788.  
  789.     if (!fEnableSpill && !g_prefs.fNoCorrectLayer3 && audioCompressor && audioCompressor->GetFormat()->wFormatTag == WAVE_FORMAT_MPEGLAYER3) {
  790.  
  791.         audioCompressor->CompensateForMP3();
  792.  
  793.         if (!(audioCorrector = new AudioL3Corrector()))
  794.             throw MyError("Dub: Unable to create audio corrector");
  795.     }
  796.  
  797. }
  798.  
  799. void Dubber::InitOutputFile(char *szFile) {
  800.  
  801.     // Do audio.
  802.  
  803.     if (aSrc && AVIout->audioOut) {
  804.         WAVEFORMATEX *outputAudioFormat;
  805.         LONG outputAudioFormatSize;
  806.  
  807.         // initialize AVI parameters...
  808.  
  809.         AVISTREAMINFOtoAVIStreamHeader(&AVIout->audioOut->streamInfo, &aSrc->streamInfo);
  810.         AVIout->audioOut->streamInfo.dwStart            = 0;
  811.         AVIout->audioOut->streamInfo.dwInitialFrames    = opt->audio.preload ? 1 : 0;
  812.  
  813.         if (!(outputAudioFormat = (WAVEFORMATEX *)AVIout->audioOut->allocFormat(outputAudioFormatSize = audioStream->GetFormatLen())))
  814.             throw MyMemoryError();
  815.  
  816.         memcpy(outputAudioFormat, audioStream->GetFormat(), audioStream->GetFormatLen());
  817.  
  818.         if (opt->audio.mode > DubAudioOptions::M_NONE) {
  819.             AVIout->audioOut->streamInfo.dwSampleSize = outputAudioFormat->nBlockAlign;
  820.             AVIout->audioOut->streamInfo.dwRate        = outputAudioFormat->nAvgBytesPerSec;
  821.             AVIout->audioOut->streamInfo.dwScale    = outputAudioFormat->nBlockAlign;
  822.             AVIout->audioOut->streamInfo.dwLength    = MulDiv(AVIout->audioOut->streamInfo.dwLength, outputAudioFormat->nSamplesPerSec, aSrc->getWaveFormat()->nSamplesPerSec);
  823.         }
  824.     }
  825.  
  826.     // Do video.
  827.  
  828.     if (vSrc && AVIout->videoOut) {
  829.         VBitmap *outputBitmap;
  830.         
  831.         if (opt->video.mode >= DubVideoOptions::M_FULL)
  832.             outputBitmap = filters.OutputBitmap();
  833.         else
  834.             outputBitmap = filters.InputBitmap();
  835.  
  836.         AVISTREAMINFOtoAVIStreamHeader(&AVIout->videoOut->streamInfo, &vSrc->streamInfo);
  837.         if (opt->video.mode > DubVideoOptions::M_NONE) {
  838.             if (fUseVideoCompression) {
  839.                 AVIout->videoOut->streamInfo.fccHandler    = compVars->fccHandler;
  840.                 AVIout->videoOut->streamInfo.dwQuality    = compVars->lQ;
  841.             } else {
  842.                 AVIout->videoOut->streamInfo.fccHandler    = mmioFOURCC('D','I','B',' ');
  843.             }
  844.         }
  845.         if (opt->video.frameRateNewMicroSecs || pInvTelecine) {
  846.             AVIout->videoOut->streamInfo.dwRate        = 1000000L; // / opt->video.frameRateDecimation;
  847.             AVIout->videoOut->streamInfo.dwScale    = vInfo.usPerFrame; //opt->video.frameRateNewMicroSecs;
  848.         } else {
  849.  
  850.             // Dividing dwRate isn't good if we get a fraction like 10/1!
  851.  
  852.             if (AVIout->videoOut->streamInfo.dwScale > 0x7FFFFFFF / opt->video.frameRateDecimation)
  853.                 AVIout->videoOut->streamInfo.dwRate        /= opt->video.frameRateDecimation;
  854.             else
  855.                 AVIout->videoOut->streamInfo.dwScale    *= opt->video.frameRateDecimation;
  856.         }
  857.         AVIout->videoOut->streamInfo.dwLength        = vInfo.end_src - vInfo.start_src;
  858.         AVIout->videoOut->streamInfo.dwLength        /= opt->video.frameRateDecimation;
  859.  
  860.         AVIout->videoOut->streamInfo.rcFrame.left    = 0;
  861.         AVIout->videoOut->streamInfo.rcFrame.top    = 0;
  862.         AVIout->videoOut->streamInfo.rcFrame.right    = (short)outputBitmap->w;
  863.         AVIout->videoOut->streamInfo.rcFrame.bottom    = (short)outputBitmap->h;
  864.  
  865.         AVIout->videoOut->setCompressed(TRUE);
  866.  
  867.         // initialize compression
  868.  
  869.         if (opt->video.mode >= DubVideoOptions::M_FASTREPACK) {
  870.             if (opt->video.mode <= DubVideoOptions::M_SLOWREPACK)
  871.                 compressorVideoFormat = (BITMAPINFO *)vSrc->getDecompressedFormat();
  872.             else {
  873.                 memset(&compressorVideoDIBFormat, 0, sizeof compressorVideoDIBFormat);
  874.                 compressorVideoDIBFormat.bmiHeader.biSize            = sizeof(BITMAPINFOHEADER);
  875.                 compressorVideoDIBFormat.bmiHeader.biWidth            = outputBitmap->w;
  876.                 compressorVideoDIBFormat.bmiHeader.biHeight            = outputBitmap->h;
  877.                 compressorVideoDIBFormat.bmiHeader.biPlanes            = 1;
  878.                 compressorVideoDIBFormat.bmiHeader.biBitCount        = iOutputDepth;
  879.                 compressorVideoDIBFormat.bmiHeader.biCompression    = BI_RGB;
  880.                 compressorVideoDIBFormat.bmiHeader.biSizeImage        = outputBitmap->pitch * outputBitmap->h;
  881.  
  882.                 compressorVideoFormat = &compressorVideoDIBFormat;
  883.             }
  884.         } else {
  885.             compressorVideoFormat = (BITMAPINFO *)vSrc->getImageFormat();
  886.         }
  887.  
  888.         // Initialize output compressor.
  889.  
  890.         _RPT0(0,"Dub: Initializing output compressor.\n");
  891.  
  892.         if (fUseVideoCompression) {
  893.             LONG formatSize;
  894.             DWORD icErr;
  895.  
  896.             formatSize = ICCompressGetFormatSize(compVars->hic, compressorVideoFormat);
  897.             if (formatSize < ICERR_OK)
  898.                 throw "Error getting compressor output format size.";
  899.  
  900.             _RPT1(0,"Video compression format size: %ld\n",formatSize);
  901.  
  902.             if (!AVIout->videoOut->allocFormat(formatSize))
  903.                 throw MyError("Out of memory");
  904.  
  905.             memset(AVIout->videoOut->getFormat(), 0, formatSize);
  906.  
  907.             if (ICERR_OK != (icErr = ICCompressGetFormat(compVars->hic,
  908.                                 (BITMAPINFOHEADER *)compressorVideoFormat,
  909.                                 AVIout->videoOut->getImageFormat())))
  910.                 throw MyICError("Output compressor",icErr);
  911.                 //throw "Error getting compressor output format.";
  912.  
  913.             if (!(pVideoPacker = new VideoSequenceCompressor()))
  914.                 throw MyMemoryError();
  915.  
  916.             pVideoPacker->init(compVars->hic, compressorVideoFormat, (BITMAPINFO *)AVIout->videoOut->getImageFormat(), compVars->lQ, compVars->lKey);
  917.             pVideoPacker->setDataRate(compVars->lDataRate*1024, vInfo.usPerFrameIn, vInfo.end_src - vInfo.start_src);
  918.             pVideoPacker->start();
  919.  
  920.             lVideoSizeEstimate = pVideoPacker->getMaxSize();
  921.  
  922.             // attempt to open output decompressor
  923.  
  924.             if (opt->video.mode <= DubVideoOptions::M_FASTREPACK)
  925.                 fShowDecompressedFrame = false;
  926.             else if (fShowDecompressedFrame = !!opt->video.fShowDecompressedFrame) {
  927.                 DWORD err;
  928.  
  929.                 if (!(outputDecompressor = ICLocate(
  930.                             'CDIV',
  931.                             AVIout->videoOut->streamInfo.fccHandler,
  932.                             AVIout->videoOut->getImageFormat(),
  933.                             &compressorVideoFormat->bmiHeader, ICMODE_DECOMPRESS))) {
  934.  
  935.                     MyError("Output video warning: Could not locate output decompressor.").post(NULL,g_szError);
  936.  
  937.                 } else if (ICERR_OK != (err = ICDecompressBegin(
  938.                         outputDecompressor,
  939.                         AVIout->videoOut->getImageFormat(),
  940.                         &compressorVideoFormat->bmiHeader))) {
  941.  
  942.                     MyICError("Output video warning", err).post(NULL,g_szError);
  943.  
  944.                     ICClose(outputDecompressor);
  945.                     outputDecompressor = NULL;
  946.  
  947.                     fShowDecompressedFrame = false;
  948.                 }
  949.             }
  950.  
  951.         } else {
  952.             BITMAPINFOHEADER *outputVideoFormat;
  953.  
  954.             if (opt->video.mode < DubVideoOptions::M_SLOWREPACK) {
  955.  
  956.                 if (vSrc->getImageFormat()->biCompression == 0xFFFFFFFF)
  957.                     throw MyError("The source video stream uses a compression algorithm which is not compatible with AVI files. "
  958.                                 "Direct stream copy cannot be used with this video stream.");
  959.  
  960.                 AVIout->videoOut->setCompressed(TRUE);
  961.                 if (!(outputVideoFormat = (BITMAPINFOHEADER *)AVIout->videoOut->allocFormat(vSrc->getFormatLen())))
  962.                     throw MyMemoryError();
  963.  
  964.                 memcpy(outputVideoFormat, vSrc->getImageFormat(), vSrc->getFormatLen());
  965.             } else {
  966.                 if (!(outputVideoFormat = (BITMAPINFOHEADER *)AVIout->videoOut->allocFormat(sizeof(BITMAPINFOHEADER))))
  967.                     throw MyMemoryError();
  968.  
  969.                 memcpy(outputVideoFormat, vSrc->getDecompressedFormat(), sizeof(BITMAPINFOHEADER));
  970.  
  971.                 if (opt->video.mode == DubVideoOptions::M_FULL) {
  972.                     outputVideoFormat->biCompression= BI_RGB;
  973.                     outputVideoFormat->biWidth        = outputBitmap->w;
  974.                     outputVideoFormat->biHeight        = outputBitmap->h;
  975.                     outputVideoFormat->biBitCount    = iOutputDepth;
  976.                     outputVideoFormat->biSizeImage    = outputBitmap->pitch * outputBitmap->h;
  977.                 }
  978.                 AVIout->videoOut->setCompressed(TRUE);
  979.  
  980.                 lVideoSizeEstimate = outputVideoFormat->biSizeImage;
  981.                 lVideoSizeEstimate = (lVideoSizeEstimate+1) & -2;
  982.             }
  983.  
  984.         }
  985.     }
  986.  
  987.     _RPT0(0,"Dub: Creating output file.\n");
  988.  
  989.     if (!AVIout->init(
  990.                 szFile,
  991.                 AVIout->videoOut ? vSrc ? compressorVideoFormat->bmiHeader.biWidth : 320 : 0, //filters.OutputBitmap()->w,
  992.                 AVIout->videoOut ? vSrc ? compressorVideoFormat->bmiHeader.biHeight : 240 : 0, //filters.OutputBitmap()->h,
  993.                 !!vSrc,
  994.                 !!aSrc,
  995.                 opt->perf.outputBufferSize,
  996.                 opt->audio.enabled))
  997.         throw MyError("Problem initializing AVI output.");
  998. }
  999.  
  1000. bool Dubber::AttemptInputOverlay(BITMAPINFOHEADER *pbih) {
  1001.     if (vSrc->setDecompressedFormat(pbih)) {
  1002.         DDSURFACEDESC ddsdOverlay;
  1003.         DDPIXELFORMAT ddpf;
  1004.         IDirectDrawSurface *lpddsOverlay;
  1005.         HRESULT res;
  1006.  
  1007.         memset(&ddpf, 0, sizeof ddpf);
  1008.         ddpf.dwSize            = sizeof ddpf;
  1009.         ddpf.dwFlags        = DDPF_FOURCC;
  1010.         ddpf.dwFourCC        = pbih->biCompression;
  1011.         ddpf.dwYUVBitCount    = pbih->biBitCount;
  1012.  
  1013.         memset(&ddsdOverlay, 0, sizeof ddsdOverlay);
  1014.         ddsdOverlay.dwSize = sizeof(ddsdOverlay);
  1015.         ddsdOverlay.dwFlags= DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH | DDSD_PIXELFORMAT;
  1016.         ddsdOverlay.ddsCaps.dwCaps = DDSCAPS_OVERLAY | DDSCAPS_VIDEOMEMORY;
  1017.         ddsdOverlay.dwWidth  = vSrc->getImageFormat()->biWidth;
  1018.         ddsdOverlay.dwHeight = vSrc->getImageFormat()->biHeight;
  1019.         ddsdOverlay.ddpfPixelFormat = ddpf;
  1020.         
  1021.         res = DDrawObtainInterface()->CreateSurface(&ddsdOverlay, &lpddsOverlay, NULL);
  1022.  
  1023.         if (DD_OK == res) {
  1024.             if (!(pdsInput = CreateDDrawSurface(lpddsOverlay))) {
  1025.                 lpddsOverlay->Release();
  1026.                 throw MyMemoryError();
  1027.             }
  1028.  
  1029.             RECT r = rInputFrame;
  1030.  
  1031.             pdsInput->SetOverlayPos(&r);
  1032.  
  1033.             return true;
  1034.         }
  1035.     }
  1036.  
  1037.     return false;
  1038. }
  1039.  
  1040. void Dubber::AttemptInputOverlays() {
  1041.     if (DDrawInitialize(g_hWnd)) {
  1042.         BITMAPINFOHEADER bih;
  1043.  
  1044.         memcpy(&bih, vSrc->getImageFormat(), sizeof(BITMAPINFOHEADER));
  1045.  
  1046.         bih.biSize            = sizeof(BITMAPINFOHEADER);
  1047.         bih.biPlanes        = 1;
  1048.         bih.biBitCount        = 16;
  1049.         bih.biSizeImage        = (bih.biWidth+(bih.biWidth&1))*2*bih.biHeight;
  1050.         bih.biXPelsPerMeter    = 0;
  1051.         bih.biYPelsPerMeter    = 0;
  1052.         bih.biClrUsed        = 0;
  1053.         bih.biClrImportant    = 0;
  1054.  
  1055.         do {
  1056.             //---- begin 16-bit YUV negotiation ----
  1057.  
  1058.             // Attempt CYUV (YUV 4:2:2, Y?Y? ordering)
  1059.  
  1060.             bih.biCompression = 'VUYC';
  1061.  
  1062.             if (AttemptInputOverlay(&bih))
  1063.                 break;
  1064.  
  1065.             // Attempt UYVY (YUV 4:2:2)
  1066.  
  1067.             bih.biCompression = 'YVYU';
  1068.  
  1069.             if (AttemptInputOverlay(&bih))
  1070.                 break;
  1071.  
  1072.             // Attempt YUYV (YUV 4:2:2)
  1073.  
  1074.             bih.biCompression = 'VYUY';
  1075.  
  1076.             if (AttemptInputOverlay(&bih))
  1077.                 break;
  1078.  
  1079.             // Attempt YUY2 (YUV 4:2:2, YUYV ordering)
  1080.  
  1081.             bih.biCompression = '2YUY';
  1082.  
  1083.             if (AttemptInputOverlay(&bih))
  1084.                 break;
  1085.  
  1086.             //---- begin 12-bit YUV negotiation ----
  1087. #if 0
  1088.             // Attempt YV12 (YUV 4:2:0)
  1089.  
  1090.             bih.biCompression = '21VY';
  1091.             bih.biSizeImage        = (bih.biWidth/2)*(bih.biHeight/2)*6;
  1092.             bih.biBitCount        = 12;
  1093.  
  1094.             if (AttemptInputOverlay(&bih))
  1095.                 break;
  1096. #endif
  1097.  
  1098.             DDrawDeinitialize();
  1099.         } while(0);
  1100.  
  1101.     }
  1102. }
  1103.  
  1104. void Dubber::AttemptInputOverlays2(void *pThis) {
  1105.     ((Dubber *)pThis)->AttemptInputOverlays();
  1106. }
  1107.  
  1108. bool Dubber::AttemptOutputOverlay() {
  1109.  
  1110.     if (!DDrawInitialize(g_hWnd))
  1111.         return false;
  1112.  
  1113.     // Try and get the pixel format for the primary surface.
  1114.  
  1115.     DDPIXELFORMAT ddpf;
  1116.  
  1117.     memset(&ddpf, 0, sizeof ddpf);
  1118.     ddpf.dwSize        = sizeof ddpf;
  1119.  
  1120.     if (DD_OK != DDrawObtainPrimary()->GetPixelFormat(&ddpf))
  1121.         return false;
  1122.  
  1123.     // Check output pixel format; we can support:
  1124.     //
  1125.     //    15-bit RGB    00007c00    000003e0    0000001f
  1126.     //    16-bit RGB    0000f800    000007e0    0000001f
  1127.     //    24-bit RGB    00ff0000    0000ff00    000000ff
  1128.     //    32-bit RGB    00ff0000    0000ff00    000000ff
  1129.  
  1130.     if (!(ddpf.dwFlags & DDPF_RGB))
  1131.         return false;
  1132.  
  1133.     const VBitmap *outputBitmap = filters.OutputBitmap();
  1134.  
  1135.     memset(&compressorVideoDIBFormat, 0, sizeof compressorVideoDIBFormat);
  1136.     bihDisplayFormat.bV4Size            = sizeof(BITMAPINFOHEADER);
  1137.     bihDisplayFormat.bV4Width            = outputBitmap->w;
  1138.     bihDisplayFormat.bV4Height            = outputBitmap->h;
  1139.     bihDisplayFormat.bV4Planes            = 1;
  1140.     bihDisplayFormat.bV4BitCount        = ddpf.dwRGBBitCount;
  1141.     bihDisplayFormat.bV4V4Compression        = BI_RGB;
  1142.     bihDisplayFormat.bV4SizeImage        = outputBitmap->pitch * outputBitmap->h;
  1143.  
  1144.     switch(ddpf.dwRGBBitCount) {
  1145.     case 16:
  1146.         if (ddpf.dwRBitMask == 0xf800 && ddpf.dwGBitMask == 0x07e0 && ddpf.dwBBitMask == 0x001f) {
  1147.             bihDisplayFormat.bV4Size            = sizeof(BITMAPV4HEADER);
  1148.             bihDisplayFormat.bV4V4Compression    = BI_BITFIELDS;
  1149.             bihDisplayFormat.bV4RedMask            = 0xf800;
  1150.             bihDisplayFormat.bV4GreenMask        = 0x07e0;
  1151.             bihDisplayFormat.bV4BlueMask        = 0x001f;
  1152.             bihDisplayFormat.bV4AlphaMask        = 0x0000;
  1153.             bihDisplayFormat.bV4CSType            = 0;
  1154.             fDisplay565 = true;
  1155.         } else if (ddpf.dwRBitMask != 0x7c00 || ddpf.dwGBitMask != 0x03e0 || ddpf.dwBBitMask != 0x001f)
  1156.             return false;
  1157.  
  1158.         break;
  1159.  
  1160.     case 24:
  1161.     case 32:
  1162.         if (ddpf.dwRBitMask != 0x00FF0000) return false;
  1163.         if (ddpf.dwGBitMask != 0x0000FF00) return false;
  1164.         if (ddpf.dwBBitMask != 0x000000FF) return false;
  1165.         break;
  1166.     }
  1167.  
  1168.     // Create off-screen surface.
  1169.  
  1170.     DDSURFACEDESC ddsdOverlay;
  1171.     IDirectDrawSurface *lpddsOutput;
  1172.  
  1173.     memset(&ddsdOverlay, 0, sizeof ddsdOverlay);
  1174.     ddsdOverlay.dwSize            = sizeof(ddsdOverlay);
  1175.     ddsdOverlay.dwFlags            = DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH | DDSD_PIXELFORMAT;
  1176.     ddsdOverlay.ddsCaps.dwCaps    = DDSCAPS_OFFSCREENPLAIN | DDSCAPS_VIDEOMEMORY;
  1177.     ddsdOverlay.dwWidth            = bihDisplayFormat.bV4Width;
  1178.     ddsdOverlay.dwHeight        = bihDisplayFormat.bV4Height;
  1179.     ddsdOverlay.ddpfPixelFormat = ddpf;
  1180.  
  1181.     if (DD_OK != DDrawObtainInterface()->CreateSurface(&ddsdOverlay, &lpddsOutput, NULL))
  1182.         return false;
  1183.  
  1184.     if (!(pdsOutput = CreateDDrawSurface(lpddsOutput))) {
  1185.         lpddsOutput->Release();
  1186.         throw MyMemoryError();
  1187.     }
  1188.  
  1189.     return true;
  1190. }
  1191.  
  1192. void Dubber::InitDirectDraw() {
  1193.  
  1194.     if (!opt->perf.useDirectDraw)
  1195.         return;
  1196.  
  1197.     // Should we try and establish a DirectDraw overlay?
  1198.  
  1199. #ifdef ASYNCHRONOUS_OVERLAY_SUPPORT
  1200.     if (opt->video.mode == DubVideoOptions::M_SLOWREPACK) {
  1201.         blitter->postAFC(0x80000000, AttemptInputOverlays2, this);
  1202.     }
  1203. #else
  1204.     AttemptInputOverlays();
  1205. #endif
  1206.  
  1207.     // How about DirectShow output acceleration?
  1208.  
  1209.     if (opt->video.mode == DubVideoOptions::M_FULL)
  1210.         AttemptOutputOverlay();
  1211.  
  1212.     if (pdsInput || pdsOutput)
  1213.         SetClientRectOffset(x_client, y_client);
  1214. }
  1215.  
  1216. void Dubber::InitDisplay() {
  1217.     _RPT0(0,"Dub: Initializing input window display.\n");
  1218.  
  1219.  
  1220.     // Check color depth of output device.  If it is 8-bit, we're
  1221.     // stuck with DrawDibDraw().  If it's at least 15 bits, then
  1222.     // we should create a DIBSection, select it into a memory
  1223.     // context, and BltBlt() to the screen instead.  It's about
  1224.     // 5-10% faster under Win95 and about 400x (!) faster under WINE.
  1225.     //
  1226.     // Okay, never mind... WINE still doesn't support DIBSection
  1227.     // windows. :(
  1228.  
  1229.     int bitsPerPel;
  1230.  
  1231.     bitsPerPel = GetDeviceCaps(hDCWindow, BITSPIXEL);
  1232.  
  1233.     if (!pdsInput && opt->video.mode > DubVideoOptions::M_FASTREPACK && !g_fWine) {
  1234.         if (bitsPerPel < 15 || vSrc->getDecompressedFormat()->biBitCount < 15
  1235.                 || !vSrc->getFrameBufferObject()) {
  1236.  
  1237.             if (hDDInput = DrawDibOpen()) {
  1238.                 if (!DrawDibBegin(hDDInput, hDCWindow, vSrc->getDecompressedFormat()->biWidth, vSrc->getDecompressedFormat()->biHeight, vSrc->getDecompressedFormat(), vSrc->getDecompressedFormat()->biWidth, vSrc->getDecompressedFormat()->biHeight, 0)) {
  1239.                     DrawDibClose(hDDInput);
  1240.                     hDDInput = NULL;
  1241.                     _RPT0(0,"Dub WARNING: could not init input video window!\n");
  1242.                 }
  1243.             }
  1244.         } else {
  1245.             if (!(hdcCompatInput = CreateCompatibleDC(hDCWindow)))
  1246.                 throw MyError("Couldn't create compatible display context for input window");
  1247.  
  1248.             if (!(hbmInput = CreateDIBSection(
  1249.                     hdcCompatInput,
  1250.                     (LPBITMAPINFO)vSrc->getDecompressedFormat(),
  1251.                     DIB_RGB_COLORS,
  1252.                     &lpvInput,
  1253.                     vSrc->getFrameBufferObject(),
  1254.                     vSrc->getFrameBufferOffset()
  1255.                 )))
  1256.                 throw MyError("Couldn't create DIB section for input window");
  1257.  
  1258.             hbmInputOld = (HBITMAP)SelectObject(hdcCompatInput, hbmInput);
  1259.         }
  1260.     }
  1261.  
  1262.     _RPT0(0,"Dub: Initializing output window display.\n");
  1263.     if (opt->video.mode == DubVideoOptions::M_FULL) {
  1264.         if (!pdsOutput && !g_fWine) {
  1265.             if (bitsPerPel < 15) {
  1266.                 if (hDDOutput = DrawDibOpen()) {
  1267.                     if (!DrawDibBegin(
  1268.                                 hDDOutput,
  1269.                                 hDCWindow,
  1270.                                 compressorVideoFormat->bmiHeader.biWidth,
  1271.                                 compressorVideoFormat->bmiHeader.biHeight,
  1272.                                 &compressorVideoFormat->bmiHeader,
  1273.                                 compressorVideoFormat->bmiHeader.biWidth,
  1274.                                 compressorVideoFormat->bmiHeader.biHeight,
  1275.                                 0)) {
  1276.  
  1277.                         DrawDibClose(hDDOutput);
  1278.                         hDDOutput = NULL;
  1279.                     }
  1280.                 }
  1281.             } else {
  1282.                 if (!(hdcCompatOutput = CreateCompatibleDC(hDCWindow)))
  1283.                     throw MyError("Couldn't create compatible display context for output window");
  1284.  
  1285.                 // check to see if DC is 565 16-bit, the only mode that does not support a line
  1286.                 // of grays... hmm... is 15 possible for bitsPerPel?
  1287.  
  1288.                 COLORREF crTmp;
  1289.  
  1290.                 fDisplay565 = false;
  1291.  
  1292.                 if (bitsPerPel==15 || bitsPerPel==16) {
  1293.                     crTmp = GetPixel(hDCWindow, 0,0);
  1294.                     SetPixel(hDCWindow,0,0,RGB(0x80, 0x88, 0x80));
  1295.  
  1296.                     if (GetPixel(hDCWindow,0,0) == RGB(0x80, 0x88, 0x80)) {
  1297.                         fDisplay565 = true;
  1298.  
  1299.                         _RPT0(0,"Display is 5-6-5 16-bit\n");
  1300.                     }
  1301.                     SetPixel(hDCWindow, 0, 0, crTmp);
  1302.                 }
  1303.  
  1304.                 memcpy(&bihDisplayFormat, compressorVideoFormat, sizeof(BITMAPINFOHEADER));
  1305.                 if (fDisplay565 && fPreview && bihDisplayFormat.bV4BitCount == 16) {
  1306.                     bihDisplayFormat.bV4Size            = sizeof(BITMAPV4HEADER);
  1307.                     bihDisplayFormat.bV4V4Compression    = BI_BITFIELDS;
  1308.                     bihDisplayFormat.bV4RedMask            = 0xf800;
  1309.                     bihDisplayFormat.bV4GreenMask        = 0x07e0;
  1310.                     bihDisplayFormat.bV4BlueMask        = 0x001f;
  1311.                     bihDisplayFormat.bV4AlphaMask        = 0x0000;
  1312.                     bihDisplayFormat.bV4CSType            = 0;
  1313.                 }
  1314.  
  1315.                 HANDLE hMapObject;
  1316.                 LONG lMapOffset;
  1317.  
  1318.                 filters.getOutputMappingParams(hMapObject, lMapOffset);
  1319.  
  1320.                 if (!(hbmOutput = CreateDIBSection(
  1321.                         hdcCompatOutput,
  1322.                         (LPBITMAPINFO)&bihDisplayFormat,
  1323.                         DIB_RGB_COLORS,
  1324.                         &lpvOutput,
  1325.                         hMapObject,
  1326.                         lMapOffset
  1327.                     )))
  1328.                     throw MyError("Couldn't create DIB section for output window");
  1329.  
  1330.                 hbmOutputOld = (HBITMAP)SelectObject(hdcCompatOutput, hbmOutput);
  1331.             }
  1332.  
  1333.             // attempt to open output decompressor
  1334. #if 0
  1335.             ICINFO info;
  1336.  
  1337.             for(int i=0; ICInfo(ICTYPE_VIDEO, i, &info); i++) {
  1338.                 char szName[256];
  1339.  
  1340.                 hicOutput = ICOpen(ICTYPE_VIDEO, info.fccHandler, ICMODE_DRAW);
  1341.                 if (!hicOutput)
  1342.                     continue;
  1343.  
  1344.                 ICGetInfo(hicOutput, &info, sizeof info);
  1345.  
  1346.                 WideCharToMultiByte(CP_ACP, 0, info.szDescription, -1, szName, sizeof szName, NULL, NULL);
  1347.  
  1348.                 if (strstr(szName, "miroVIDEO")) {
  1349.  
  1350.                     if (hicOutput) {
  1351.                         ICDrawBegin(hicOutput, ICDRAW_HDC, NULL, g_hWnd, hDCWindow, 0, 0,
  1352.                                 compressorVideoFormat->bmiHeader.biWidth,
  1353.                                 compressorVideoFormat->bmiHeader.biHeight,
  1354.                                 AVIout->videoOut->getImageFormat(),
  1355.                                 0,
  1356.                                 0,
  1357.                                 compressorVideoFormat->bmiHeader.biWidth,
  1358.                                 compressorVideoFormat->bmiHeader.biHeight,
  1359.                                 1000000,
  1360.                                 vInfo.usPerFrame);
  1361.  
  1362.                         ICDrawStart(hicOutput);
  1363.                     }
  1364.  
  1365.                     break;
  1366.                 }
  1367.  
  1368.                 ICClose(hicOutput);
  1369.                 hicOutput = NULL;
  1370.             }
  1371. #endif
  1372.         }
  1373.  
  1374.         if (opt->video.fHistogram) {
  1375.             inputHisto = new Histogram(hDCWindow, 128);
  1376.             outputHisto = new Histogram(hDCWindow, 128);
  1377.         }
  1378.     }
  1379.  
  1380. }
  1381.  
  1382. bool Dubber::NegotiateFastFormat(BITMAPINFOHEADER *pbih) {
  1383.     return vSrc->setDecompressedFormat(pbih) &&
  1384.             ICERR_OK == ICCompressQuery(compVars->hic, pbih, NULL);
  1385. }
  1386.  
  1387. bool Dubber::NegotiateFastFormat(int depth) {
  1388.     return vSrc->setDecompressedFormat(depth) &&
  1389.             ICERR_OK == ICCompressQuery(compVars->hic, vSrc->getDecompressedFormat(), NULL);
  1390. }
  1391.  
  1392. void Dubber::InitSelectInputFormat() {
  1393.     //    DIRECT:            Don't care.
  1394.     //    FASTREPACK:        Negotiate with output compressor.
  1395.     //    SLOWREPACK:        [Dub]        Use selected format.
  1396.     //                    [Preview]    Negotiate with display driver.
  1397.     //    FULL:            Use selected format.
  1398.  
  1399.     if (opt->video.mode == DubVideoOptions::M_NONE)
  1400.         return;
  1401.  
  1402.     if (opt->video.mode == DubVideoOptions::M_FASTREPACK && fUseVideoCompression) {
  1403.         BITMAPINFOHEADER bih;
  1404.  
  1405.         // Begin decompressor to compressor format negotiation.
  1406.         //
  1407.  
  1408.         // Attempt IF09.
  1409.  
  1410. #if 0
  1411.         int blocks;
  1412.  
  1413.         memcpy(&bih, vSrc->getImageFormat(), sizeof(BITMAPINFOHEADER));
  1414.  
  1415.         blocks = ((bih.biWidth+3)/4)*((bih.biHeight+3)/4);
  1416.  
  1417.         bih.biSize            = sizeof(BITMAPINFOHEADER);
  1418.         bih.biPlanes        = 3;
  1419.         bih.biBitCount        = 9;        // does it matter?
  1420.         bih.biCompression    = '90FI';
  1421.         bih.biSizeImage        = blocks*(16 + 2) + ((blocks+31)/32)*4;
  1422.         bih.biXPelsPerMeter    = 0;
  1423.         bih.biYPelsPerMeter    = 0;
  1424.         bih.biClrUsed        = 0;
  1425.         bih.biClrImportant    = 0;
  1426.  
  1427.         if (NegotiateFastFormat(&bih))
  1428.             return;
  1429. #endif
  1430.  
  1431.         // Attempt UYVY.
  1432.  
  1433.         memcpy(&bih, vSrc->getImageFormat(), sizeof(BITMAPINFOHEADER));
  1434.  
  1435.         bih.biSize            = sizeof(BITMAPINFOHEADER);
  1436.         bih.biPlanes        = 1;
  1437.         bih.biBitCount        = 16;
  1438.         bih.biCompression    = 'YVYU';
  1439.         bih.biSizeImage        = (bih.biWidth+(bih.biWidth&1))*2*bih.biHeight;
  1440.         bih.biXPelsPerMeter    = 0;
  1441.         bih.biYPelsPerMeter    = 0;
  1442.         bih.biClrUsed        = 0;
  1443.         bih.biClrImportant    = 0;
  1444.  
  1445.         if (NegotiateFastFormat(&bih))
  1446.             return;
  1447.  
  1448.         // Attempt YUYV.
  1449.  
  1450.         bih.biCompression    = 'VYUY';
  1451.  
  1452.         if (NegotiateFastFormat(&bih))
  1453.             return;
  1454.  
  1455.         // Attempt YUY2.
  1456.  
  1457.         bih.biCompression    = '2YUY';
  1458.  
  1459.         if (NegotiateFastFormat(&bih))
  1460.             return;
  1461.  
  1462.         // Attempt RGB format negotiation.
  1463.  
  1464.         if (NegotiateFastFormat(16+8*opt->video.inputDepth))
  1465.             return;
  1466.  
  1467.         if (NegotiateFastFormat(24))
  1468.             return;
  1469.         if (NegotiateFastFormat(32))
  1470.             return;
  1471.         if (NegotiateFastFormat(16))
  1472.             return;
  1473.         if (NegotiateFastFormat(8))
  1474.             return;
  1475.  
  1476.         throw MyError("Video format negotiation failed: use slow-repack or full mode.");
  1477.     }
  1478.  
  1479.     // Negotiate RGB format.
  1480.  
  1481.     if (!vSrc->setDecompressedFormat(16+8*opt->video.inputDepth))
  1482.         if (!vSrc->setDecompressedFormat(32))
  1483.             if (!vSrc->setDecompressedFormat(24))
  1484.                 if (!vSrc->setDecompressedFormat(16))
  1485.                     if (!vSrc->setDecompressedFormat(8))
  1486.                         throw MyError("VCM cannot decompress to a format we can handle.");
  1487. }
  1488.  
  1489. void Dubber::Init(VideoSource *video, AudioSource *audio, AVIOutput *out, char *szFile, HDC hDC, COMPVARS *videoCompVars) {
  1490.  
  1491.     aSrc                = audio;
  1492.     vSrc                = video;
  1493.     AVIout                = out;
  1494.  
  1495.     fPreview            = !!AVIout->isPreview();
  1496.  
  1497.     compVars            = videoCompVars;
  1498.     hDCWindow            = hDC;
  1499.     fUseVideoCompression = !fPreview && opt->video.mode>DubVideoOptions::M_NONE && compVars && (compVars->dwFlags & ICMF_COMPVARS_VALID) && compVars->hic;
  1500. //    fUseVideoCompression = opt->video.mode>DubVideoOptions::M_NONE && compVars && (compVars->dwFlags & ICMF_COMPVARS_VALID) && compVars->hic;
  1501.  
  1502.     // check the mode; if we're using DirectStreamCopy or Fast mode, we'll need to
  1503.     // align the subset to keyframe boundaries!
  1504.  
  1505.     if (vSrc && inputSubset) {
  1506.         inputSubsetActive = inputSubset;
  1507.  
  1508.         if (inputSubset && opt->video.mode < DubVideoOptions::M_SLOWREPACK) {
  1509.             FrameSubsetNode *pfsn;
  1510.  
  1511.             if (!(inputSubsetActive = inputSubsetAlloc = new FrameSubset()))
  1512.                 throw MyMemoryError();
  1513.  
  1514.             pfsn = inputSubset->getFirstFrame();
  1515.             while(pfsn) {
  1516.                 long end = pfsn->start + pfsn->len;
  1517.                 long start = vSrc->nearestKey(pfsn->start + vSrc->lSampleFirst) - vSrc->lSampleFirst;
  1518.  
  1519.                 _RPT3(0,"   subset: %5d[%5d]-%-5d\n", pfsn->start, start, pfsn->start+pfsn->len-1);
  1520.                 inputSubsetActive->addRangeMerge(start, end-start);
  1521.  
  1522.                 pfsn = inputSubset->getNextFrame(pfsn);
  1523.             }
  1524.  
  1525. #ifdef _DEBUG
  1526.             pfsn = inputSubsetActive->getFirstFrame();
  1527.  
  1528.             while(pfsn) {
  1529.                 _RPT2(0,"   padded subset: %8d-%-8d\n", pfsn->start, pfsn->start+pfsn->len-1);
  1530.                 pfsn = inputSubsetActive->getNextFrame(pfsn);
  1531.             }
  1532. #endif
  1533.         }
  1534.     }
  1535.  
  1536.     // initialize stream values
  1537.  
  1538.     InitStreamValuesStatic(vInfo, aInfo, video, audio, opt, inputSubsetActive);
  1539.  
  1540.     vInfo.usPerFrameNoTelecine = vInfo.usPerFrame;
  1541.     if (opt->video.mode >= DubVideoOptions::M_FULL && opt->video.fInvTelecine) {
  1542.         vInfo.usPerFrame = MulDiv(vInfo.usPerFrame, 30, 24);
  1543.     }
  1544.  
  1545.     lSpillVideoOk = vInfo.cur_src;
  1546.     lSpillAudioOk = aInfo.cur_src;
  1547.  
  1548.     _RPT0(0,"Dub: Initializing AVI output.\n");
  1549.  
  1550.     if (!(AVIout->initOutputStreams())) throw MyError("Out of memory");
  1551.  
  1552.     _RPT0(0,"Dub: Creating blitter.\n");
  1553.  
  1554.     if (g_syncroBlit || !fPreview)
  1555.         blitter = new AsyncBlitter();
  1556.     else
  1557.         blitter = new AsyncBlitter(8);
  1558.  
  1559.     if (!blitter) throw MyError("Couldn't create AsyncBlitter");
  1560.  
  1561.     blitter->pulse();
  1562.  
  1563.     // Select an appropriate input format.  This is really tricky...
  1564.  
  1565.     vInfo.fAudioOnly = true;
  1566.     if (vSrc && AVIout->videoOut) {
  1567.         InitSelectInputFormat();
  1568.         vInfo.fAudioOnly = false;
  1569.     }
  1570.  
  1571.     iOutputDepth = 16+8*opt->video.outputDepth;
  1572.  
  1573.     // Initialize filter system.
  1574.  
  1575.     nVideoLag = nVideoLagNoTelecine = 0;
  1576.  
  1577.     if (vSrc) {
  1578.         BITMAPINFOHEADER *bmih = vSrc->getDecompressedFormat();
  1579.  
  1580.         filters.initLinearChain(&g_listFA, (Pixel *)(bmih+1), bmih->biWidth, bmih->biHeight, 32 /*bmih->biBitCount*/, iOutputDepth);
  1581.  
  1582.         fsi.lMicrosecsPerFrame        = vInfo.usPerFrame;
  1583.         fsi.lMicrosecsPerSrcFrame    = vInfo.usPerFrameIn;
  1584.         fsi.lCurrentFrame            = 0;
  1585.  
  1586.         if (filters.ReadyFilters(&fsi))
  1587.             throw "Error readying filters.";
  1588.  
  1589.         fFiltersOk = TRUE;
  1590.  
  1591.         nVideoLagNoTelecine = nVideoLag = filters.getFrameLag();
  1592.  
  1593.         // Inverse telecine?
  1594.  
  1595.         if (opt->video.mode >= DubVideoOptions::M_FULL && opt->video.fInvTelecine) {
  1596.             if (!(pInvTelecine = CreateVideoTelecineRemover(filters.InputBitmap(), !opt->video.fIVTCMode, opt->video.nIVTCOffset, opt->video.fIVTCPolarity)))
  1597.                 throw MyMemoryError();
  1598.  
  1599.             nVideoLag += 10;
  1600.         }
  1601.     }
  1602.  
  1603.     nVideoLagPreload = nVideoLagNoTelecine;
  1604.  
  1605.     // initialize directdraw display if in preview
  1606.  
  1607.     if (fPreview)
  1608.         InitDirectDraw();
  1609.  
  1610.     // initialize input decompressor
  1611.  
  1612.     if (vSrc && AVIout->videoOut) {
  1613.  
  1614.         _RPT0(0,"Dub: Initializing input decompressor.\n");
  1615.  
  1616.         vSrc->streamBegin(fPreview);
  1617.         fVDecompressionOk = TRUE;
  1618.  
  1619.     }
  1620.  
  1621.     // Initialize audio.
  1622.  
  1623.     _RPT0(0,"Dub: Initializing audio.\n");
  1624.  
  1625.     if (aSrc)
  1626.         InitAudioConversionChain();
  1627.  
  1628.     // Initialize output file.
  1629.  
  1630.     InitOutputFile(szFile);
  1631.  
  1632.     // Initialize input window display.
  1633.  
  1634.     if (vSrc && AVIout->videoOut)
  1635.         InitDisplay();
  1636.  
  1637.     // Allocate input buffer.
  1638.  
  1639.     if (!(inputBuffer = allocmem(inputBufferSize = 65536)))
  1640.         throw MyMemoryError();
  1641.  
  1642.     // Create a pipe.
  1643.  
  1644.     _RPT0(0,"Dub: Creating data pipe.\n");
  1645.  
  1646.     if (!(pipe = new AVIPipe(opt->perf.pipeBufferCount, 16384)) || !pipe->isOkay())
  1647.         throw MyError("Couldn't create pipe");
  1648.  
  1649.     // Create events.
  1650.  
  1651.     _RPT0(0,"Dub: Creating events.\n");
  1652.  
  1653.     if (!(hEventAbortOk = CreateEvent(NULL,FALSE,FALSE,NULL)))
  1654.         throw MyError("Couldn't create abort event");
  1655. }
  1656.  
  1657. void Dubber::Go(int iPriority) {
  1658.     OSVERSIONINFO ovi;
  1659.  
  1660.     // check the version.  if NT, don't touch the processing priority!
  1661.  
  1662.     ovi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
  1663.  
  1664.     fNoProcessingPriority = GetVersionEx(&ovi) && ovi.dwPlatformId == VER_PLATFORM_WIN32_NT;
  1665.  
  1666.     if (!iPriority)
  1667.         iPriority = fNoProcessingPriority || !AVIout->isPreview() ? 5 : 6;
  1668.  
  1669.     this->iPriority = iPriority;
  1670.  
  1671.     // Reset timer.
  1672.  
  1673.     _XRPT0(0,"Dub: Starting multimedia timer.\n");
  1674.  
  1675.     if (fPreview) {
  1676. //        timerInterval = MulDiv(AVIout->videoOut->streamInfo.dwScale, 1000L, AVIout->videoOut->streamInfo.dwRate);
  1677.         timerInterval = vInfo.usPerFrame / 1000;
  1678.  
  1679.         if (opt->video.fSyncToAudio || opt->video.nPreviewFieldMode) {
  1680. //            blitter->setPulseCallback(PulseCallbackProc, this);
  1681.  
  1682.             timerInterval /= 2;
  1683.         }
  1684.  
  1685. //        timerInterval /= 2;
  1686.  
  1687.         if (TIMERR_NOERROR != timeBeginPeriod(timerInterval)) {
  1688.             timerInterval = 0;
  1689.             throw MyError("Couldn't initialize timer!");
  1690.         }
  1691.  
  1692.         timer_counter = 0;
  1693.         timer_period = timerInterval;
  1694.  
  1695.         if (!(timerID = timeSetEvent(timerInterval, timerInterval, DubFrameTimerProc, (DWORD)this, TIME_PERIODIC)))
  1696.             throw MyError("Couldn't start timer!");
  1697.  
  1698.     }
  1699.  
  1700.     // Initialize threads.
  1701.  
  1702.     _XRPT0(0,"Dub: Kickstarting threads.\n");
  1703.  
  1704.     if (!(hThreadProcessor = (HANDLE)_beginthread(ProcessingThreadKickstart, 0, (void *)this)))
  1705.         throw MyError("Couldn't create processing thread");
  1706.  
  1707. //    if (fPreview && !fNoProcessingPriority)
  1708.     SetThreadPriority(hThreadProcessor, g_iPriorities[iPriority-1][0]);
  1709.  
  1710.     // Wait for the thread count to increment to 1.  Otherwise, it's possible for
  1711.     // one of the later initialization events to fail, and the end() function to
  1712.     // be called before the first thread is even scheduled.  If this happens,
  1713.     // the thread will be left dangling.
  1714.  
  1715.     while(!lThreadsActive) Sleep(100);
  1716.  
  1717.     // Continue with other threads.
  1718.  
  1719.     if (!(hThreadMain = (HANDLE)_beginthread(MainThreadKickstart, 0, (void *)this)))
  1720.         throw "Couldn't create main dubbing thread";
  1721.  
  1722.     SetThreadPriority(hThreadMain, g_iPriorities[iPriority-1][1]);
  1723.  
  1724.     // Create status window during the dub.
  1725.  
  1726.     _XRPT0(0,"Dub: Creating status window.\n");
  1727.  
  1728.     pStatusHandler->InitLinks(&aInfo, &vInfo, aSrc, vSrc, pInput, audioStatusStream, this, opt);
  1729.  
  1730.     if (hwndStatus = pStatusHandler->Display(NULL, iPriority)) {
  1731.         MSG msg;
  1732.  
  1733.         // NOTE: WM_QUIT messages seem to get blocked if the window is dragging/sizing
  1734.         //         or has a menu.
  1735.  
  1736.         DEFINE_SP(sp);
  1737.  
  1738.         while (!fAbort && GetMessage(&msg, (HWND) NULL, 0, 0)) { 
  1739.  
  1740.             CHECK_STACK(sp);
  1741.  
  1742.             if (guiCheckDialogs(&msg)) continue;
  1743.             if (!IsWindow(hwndStatus) || !IsDialogMessage(hwndStatus, &msg)) { 
  1744.                 TranslateMessage(&msg); 
  1745.                 DispatchMessage(&msg); 
  1746.             }
  1747.         }
  1748.  
  1749.     }
  1750.  
  1751.     Stop();
  1752.  
  1753.     if (fError)
  1754.         throw err;
  1755.  
  1756.     pStatusHandler->SetLastPosition(vInfo.cur_proc_src);
  1757. //    if (positionCallback)
  1758. //        positionCallback(vInfo.start_src, vInfo.cur_proc_src < vInfo.start_src ? vInfo.start_src : vInfo.cur_proc_src > vInfo.end_src ? vInfo.end_src : vInfo.cur_proc_src, vInfo.end_src);
  1759.  
  1760.     _RPT0(0,"Dub: exit.\n");
  1761. }
  1762.  
  1763. //////////////////////////////////////////////
  1764.  
  1765. static void DestroyIDDrawSurface(void *pv) {
  1766.     delete (IDDrawSurface *)pv;
  1767.     DDrawDeinitialize();
  1768. }
  1769.  
  1770. void Dubber::Stop() {
  1771.     bool fSkipDXShutdown = false;
  1772.  
  1773.     if (InterlockedExchange(&lStopCount, 1))
  1774.         return;
  1775.  
  1776.     _XRPT0(0,"Dub: Beginning stop process.\n");
  1777.  
  1778.     if (pipe)
  1779.         pipe->abort();
  1780.  
  1781.     if (blitter)
  1782.         blitter->flush();
  1783.  
  1784.     _XRPT0(0,"Dub: Killing threads.\n"); DEBUG_SLEEP;
  1785.  
  1786.     fAbort = TRUE;
  1787.     while(lThreadsActive) {
  1788.         DWORD dwRes;
  1789.  
  1790.         dwRes = MsgWaitForMultipleObjects(1, &hEventAbortOk, FALSE, 10000, QS_ALLINPUT);
  1791.  
  1792.         if (WAIT_OBJECT_0+1 == dwRes)
  1793.             guiDlgMessageLoop(hwndStatus);
  1794.         else if (WAIT_TIMEOUT == dwRes) {
  1795.             MessageBox(g_hWnd, "Thread deadlock detected attempting to abort - killing process.", "VirtualDub Internal Error", MB_ICONEXCLAMATION|MB_OK);
  1796.             ExitProcess(0);
  1797.         }
  1798.  
  1799. _XRPT0(0,"\tDub: Threads still active\n");
  1800.  
  1801.         _RPT1(0,"\tDub: %ld threads active\n", lThreadsActive);
  1802.  
  1803. #ifdef _DEBUG
  1804.         if (blitter) _RPT1(0,"\t\tBlitter locks active: %08lx\n", blitter->lock_state);
  1805. #endif
  1806.     }
  1807.  
  1808.     if (blitter)
  1809.         blitter->flush();
  1810.  
  1811.     _XRPT0(0,"Dub: Freezing status handler.\n"); DEBUG_SLEEP;
  1812.  
  1813.     if (pStatusHandler)
  1814.         pStatusHandler->Freeze();
  1815.  
  1816.     _XRPT0(0,"Dub: Killing timers.\n"); DEBUG_SLEEP;
  1817.  
  1818.     if (timerID)        { timeKillEvent(timerID);        timerID = NULL; }
  1819.     if (timerInterval)    { timeEndPeriod(timerInterval);    timerInterval = NULL; }
  1820.  
  1821.     if (hicOutput) {
  1822.         ICDrawStop(hicOutput);
  1823.         ICDrawFlush(hicOutput);
  1824.         ICDrawEnd(hicOutput);
  1825.         ICClose(hicOutput);
  1826.         hicOutput = NULL;
  1827.     }
  1828.  
  1829.     if (pVideoPacker) {
  1830.         _RPT0(0,"Dub: Ending frame compression.\n");
  1831.  
  1832.         delete pVideoPacker;
  1833.  
  1834.         pVideoPacker = NULL;
  1835.     }
  1836.  
  1837.     if (pdsInput) {
  1838.         _XRPT0(0,"Dub: Destroying input overlay.\n");
  1839.  
  1840. #ifdef ASYNCHRONOUS_OVERLAY_SUPPORT
  1841.         blitter->postAFC(0x80000000, DestroyIDDrawSurface, (void *)pdsInput);
  1842.         pdsInput = NULL;
  1843.         fSkipDXShutdown = true;
  1844. #else
  1845.         delete pdsInput;
  1846.         pdsInput = NULL;
  1847. #endif
  1848.     }
  1849.  
  1850.     _XRPT0(0,"Dub: Deallocating resources.\n"); DEBUG_SLEEP;
  1851.  
  1852.     if (pipe)            { delete pipe; pipe = NULL; }
  1853.     if (blitter)        { delete blitter; blitter=NULL; }
  1854.  
  1855.     GdiFlush();
  1856.  
  1857.     filters.DeinitFilters();
  1858.  
  1859.     if (fVDecompressionOk)    { vSrc->streamEnd(); }
  1860.     if (fADecompressionOk)    { aSrc->streamEnd(); }
  1861.  
  1862.     if (hEventAbortOk)    { CloseHandle(hEventAbortOk); hEventAbortOk = NULL; }
  1863.     if (inputBuffer)    { freemem(inputBuffer); inputBuffer = NULL; }
  1864.     if (audioBuffer)    { freemem(audioBuffer); audioBuffer = NULL; }
  1865.  
  1866.     if (audioCorrector)            { delete audioCorrector; audioCorrector = NULL; }
  1867.     if (audioCompressor)        { delete audioCompressor; audioCompressor = NULL; }
  1868.     if (audioSubsetFilter)        { delete audioSubsetFilter; audioSubsetFilter = NULL; }
  1869.     if (audioStreamAmplifier)    { delete audioStreamAmplifier; audioStreamAmplifier = NULL; }
  1870.     if (audioStreamResampler)    { delete audioStreamResampler; audioStreamResampler = NULL; }
  1871.     if (audioStreamConverter)    { delete audioStreamConverter; audioStreamConverter = NULL; }
  1872.     if (audioStreamSource)        { delete audioStreamSource; audioStreamSource = NULL; }
  1873.  
  1874.     if (inputSubsetAlloc)        { delete inputSubsetAlloc; inputSubsetAlloc = NULL; }
  1875.  
  1876.     _XRPT0(0,"Dub: Releasing display elements.\n"); DEBUG_SLEEP;
  1877.  
  1878.     if (inputHisto)                { delete inputHisto; inputHisto = NULL; }
  1879.     if (outputHisto)            { delete outputHisto; outputHisto = NULL; }
  1880.  
  1881.     if (hDDInput)                { DrawDibClose(hDDInput); hDDInput = NULL; }
  1882.     if (hDDOutput)                { DrawDibClose(hDDOutput); hDDOutput = NULL; }
  1883.  
  1884.     // deinitialize DirectDraw
  1885.  
  1886.     _XRPT0(0,"Dub: Deinitializing DirectDraw.\n");
  1887.  
  1888.     if (pdsOutput)    delete pdsOutput;    pdsOutput = NULL;
  1889.  
  1890.     if (!fSkipDXShutdown)    DDrawDeinitialize();
  1891.  
  1892.     // A pile of **** to Microsoft for a buggy CreateDIBSection().
  1893.     //
  1894.     // Seems that if you provide a handle to a file mapping section with
  1895.     // an offset >=64K under NT4, it fails to unmap the view, resulting
  1896.     // in a memory leak if you don't do it yourself...
  1897.     //
  1898.     // This bug was fixed in Windows 98 and NT5.
  1899.  
  1900.     if (hbmInput) {
  1901.         SelectObject(hdcCompatInput, hbmInputOld);
  1902.         DeleteObject(hbmInput);
  1903.         UnmapViewOfFile(lpvInput);
  1904.         hbmInput = NULL;
  1905.     }
  1906.     if (hbmOutput) {
  1907.         SelectObject(hdcCompatOutput, hbmOutputOld);
  1908.         DeleteObject(hbmOutput);
  1909.         UnmapViewOfFile(lpvOutput);
  1910.         hbmOutput = NULL;
  1911.     }
  1912.  
  1913.     if (hdcCompatInput)            { DeleteDC(hdcCompatInput); hdcCompatInput = NULL; }
  1914.     if (hdcCompatOutput)        { DeleteDC(hdcCompatOutput); hdcCompatOutput = NULL; }
  1915.  
  1916.     filters.DeallocateBuffers();
  1917.     
  1918.     delete pInvTelecine;    pInvTelecine = NULL;
  1919.  
  1920.     if (outputDecompressor)    {
  1921.         ICDecompressEnd(outputDecompressor);
  1922.         ICClose(outputDecompressor);
  1923.         outputDecompressor = NULL;
  1924.     }
  1925.  
  1926.     if (AVIout) {
  1927.         delete AVIout;
  1928.         AVIout = NULL;
  1929.     }
  1930.  
  1931.     //_RPT0(0,"Dub: Stop complete.\n");
  1932. //    OutputDebugString("Dub: Stop complete.\n");
  1933.  
  1934. #ifdef STOP_SPEED_DEBUGGING
  1935.     __asm {
  1936.         rdtsc
  1937.         mov dword ptr stop_time+0,eax
  1938.         mov dword ptr stop_time+4,edx
  1939.     }
  1940.  
  1941.     {
  1942.         char buf[128];
  1943.  
  1944.         wsprintf(buf, "braking time: %d ms\n", (int)((stop_time - start_time)/300000000));
  1945.         OutputDebugString(buf);
  1946.     }
  1947. #endif
  1948. }
  1949.  
  1950. ///////////////////////////////////////////////////////////////////
  1951.  
  1952. static long g_lPulseClock;
  1953.  
  1954. void CALLBACK Dubber::DubFrameTimerProc(UINT uID, UINT uMsg, DWORD dwUser, DWORD dw1, DWORD dw2) {
  1955.     Dubber *thisPtr = (Dubber *)dwUser;
  1956.  
  1957.     if (thisPtr->opt->video.fSyncToAudio) {
  1958.         long lActualPoint;
  1959.  
  1960.         lActualPoint = ((AVIAudioPreviewOutputStream *)thisPtr->AVIout->audioOut)->getPosition();
  1961.  
  1962.         if (!((AVIAudioPreviewOutputStream *)thisPtr->AVIout->audioOut)->isFrozen()) {
  1963.             if (thisPtr->opt->video.nPreviewFieldMode) {
  1964.                 g_lPulseClock = MulDiv(lActualPoint, 2000, thisPtr->vInfo.usPerFrame);
  1965.  
  1966.                 g_lPulseClock += thisPtr->nVideoLagNoTelecine*2;
  1967.             } else {
  1968.                 g_lPulseClock = MulDiv(lActualPoint, 1000, thisPtr->vInfo.usPerFrame);
  1969.  
  1970.                 g_lPulseClock += thisPtr->nVideoLagNoTelecine;
  1971.             }
  1972.  
  1973.             if (g_lPulseClock<0)
  1974.                 g_lPulseClock = 0;
  1975.  
  1976.             if (lActualPoint != -1) {
  1977.                 thisPtr->blitter->setPulseClock(g_lPulseClock);
  1978.                 thisPtr->fSyncToAudioEvenClock = false;
  1979.                 return;
  1980.             }
  1981.         }
  1982.  
  1983.         // Hmm... we have no clock!
  1984.  
  1985.         if (thisPtr->fSyncToAudioEvenClock || thisPtr->opt->video.nPreviewFieldMode) {
  1986.             if (thisPtr->blitter) {
  1987.                 thisPtr->blitter->pulse();
  1988.             }
  1989.             ++thisPtr->iFrameDisplacement;
  1990.         }
  1991.  
  1992.         thisPtr->fSyncToAudioEvenClock = !thisPtr->fSyncToAudioEvenClock;
  1993.  
  1994.         return;
  1995.     }
  1996.  
  1997.  
  1998.     if (thisPtr->blitter) thisPtr->blitter->pulse();
  1999.  
  2000. #if 0
  2001.     if (thisPtr->blitter) {
  2002.         if (timeGetTime() - thisPtr->timer_counter >= thisPtr->timer_period) {
  2003.             thisPtr->timer_counter += thisPtr->timer_period;
  2004.             thisPtr->blitter->pulse();
  2005.         }
  2006.     }
  2007. #endif
  2008. }
  2009.  
  2010. int Dubber::PulseCallbackProc(void *_thisPtr, DWORD framenum) {
  2011. #if 1
  2012.     return AsyncBlitter::PCR_OKAY;
  2013. #else
  2014.     Dubber *thisPtr = (Dubber *)_thisPtr;
  2015.     long lAudioPoint1, lAudioPoint2, lActualPoint;
  2016.  
  2017.     lAudioPoint1 = MulDiv(framenum, thisPtr->vInfo.usPerFrame, 1000);
  2018.     lAudioPoint2 = MulDiv(framenum+3, thisPtr->vInfo.usPerFrame, 1000);
  2019.  
  2020.     lActualPoint = ((AVIAudioPreviewOutputStream *)thisPtr->AVIout->audioOut)->getPosition();
  2021.  
  2022.     if (lActualPoint <= 0) return AsyncBlitter::PCR_OKAY;
  2023.  
  2024. //    _RPT3(0,"%d %d %d\n", lAudioPoint1, lActualPoint, lAudioPoint2);
  2025.  
  2026.     if      (lActualPoint <  lAudioPoint1)    return AsyncBlitter::PCR_WAIT;
  2027. //    else if (lActualPoint >= lAudioPoint2)    return AsyncBlitter::PCR_NOBLIT;
  2028.     else                                    return AsyncBlitter::PCR_OKAY;
  2029. #endif
  2030. }
  2031.  
  2032. /////////////////////////////////////////////////////////////
  2033.  
  2034. void Dubber::ResizeInputBuffer(long bufsize) {
  2035.     inputBufferSize = (bufsize+65535) & 0xFFFF0000L;
  2036.  
  2037.     if (!(inputBuffer = reallocmem(inputBuffer, inputBufferSize)))
  2038.         throw "Error reallocating input buffer.\n";
  2039. }
  2040.  
  2041. void Dubber::ResizeAudioBuffer(long bufsize) {
  2042.     audioBufferSize = (bufsize+65535) & 0xFFFF0000L;
  2043.  
  2044.     if (!(audioBuffer = reallocmem(audioBuffer, audioBufferSize)))
  2045.         throw "Error reallocating audio buffer.\n";
  2046. }
  2047.  
  2048. void Dubber::ReadVideoFrame(long lVStreamPos, BOOL preload) {
  2049.     LONG lActualBytes;
  2050.     int hr;
  2051.  
  2052.     void *buffer;
  2053.     int handle;
  2054.  
  2055.     LONG lSize;
  2056.  
  2057.     if (fPhantom) {
  2058.         buffer = pipe->getWriteBuffer(0, &handle, INFINITE);
  2059.         if (!buffer) return;    // hmm, aborted...
  2060.  
  2061.         pipe->postBuffer(0, lVStreamPos,
  2062.             (vSrc->isKey(lVStreamPos) ? 0 : 1)
  2063.             +(preload ? 2 : 0),
  2064.             handle);
  2065.  
  2066.         return;
  2067.     }
  2068.  
  2069. //    _RPT2(0,"Reading frame %ld (%s)\n", lVStreamPos, preload ? "preload" : "process");
  2070.  
  2071.     hr = vSrc->read(lVStreamPos, 1, NULL, 0x7FFFFFFF, &lSize, NULL);
  2072.     if (hr) throw MyAVIError("Dub/IO-Video", hr);
  2073.  
  2074.     // Add 4 bytes -- otherwise, we can get crashes with uncompressed video because
  2075.     // the bitmap routines expect to be able to read 4 bytes out.
  2076.  
  2077.     buffer = pipe->getWriteBuffer(lSize+4, &handle, INFINITE);
  2078.     if (!buffer) return;    // hmm, aborted...
  2079.  
  2080.     hr = vSrc->read(lVStreamPos, 1, buffer, lSize,    &lActualBytes,NULL); 
  2081.     if (hr) throw MyAVIError("Dub/IO-Video", hr);
  2082.  
  2083.     if (opt->video.mode > DubVideoOptions::M_NONE)
  2084.         i64SegmentSize += lVideoSizeEstimate;
  2085.     else
  2086.         i64SegmentSize += lActualBytes + (lActualBytes&1);
  2087.  
  2088.     i64SegmentSize += 24;
  2089.  
  2090.     pipe->postBuffer(lActualBytes, lVStreamPos,
  2091.         (vSrc->isKey(lVStreamPos) ? 0 : 1)
  2092.         +(preload ? 2 : 0),
  2093. //        +((lVStreamPos % opt->video.frameRateDecimation) || preload ? 2 : 0),
  2094.         handle);
  2095.  
  2096.  
  2097. }
  2098.  
  2099. void Dubber::ReadNullVideoFrame(long lVStreamPos) {
  2100.     void *buffer;
  2101.     int handle;
  2102.  
  2103.     buffer = pipe->getWriteBuffer(1, &handle, INFINITE);
  2104.     if (!buffer) return;    // hmm, aborted...
  2105.  
  2106.     pipe->postBuffer(0, lVStreamPos,
  2107.         (vSrc->isKey(lVStreamPos) ? 0 : 1),
  2108. //        +((lVStreamPos % opt->video.frameRateDecimation)? 2 : 0),
  2109.         handle);
  2110.  
  2111.     i64SegmentSize += 24 + lVideoSizeEstimate;
  2112.  
  2113. //    _RPT0(0,"posted.\n");
  2114. }
  2115.  
  2116. long Dubber::ReadAudio(long& lAStreamPos, long samples) {
  2117.     LONG lActualBytes=0;
  2118.     LONG lActualSamples=0;
  2119.  
  2120.     void *buffer;
  2121.     int handle;
  2122.     long len;
  2123.  
  2124.     LONG ltActualBytes, ltActualSamples;
  2125.     char *destBuffer;
  2126.  
  2127.     if (audioCompressor) {
  2128.         void *holdBuffer;
  2129.         LONG lSrcSamples;
  2130.  
  2131.         holdBuffer = audioCompressor->Compress(samples, &lSrcSamples, &lActualBytes, &lActualSamples);
  2132.  
  2133.         if (audioCorrector)
  2134.             audioCorrector->Process(holdBuffer, lActualBytes);
  2135.  
  2136.         buffer = pipe->getWriteBuffer(lActualBytes, &handle, INFINITE);
  2137.         if (!buffer) return 0;
  2138.  
  2139.         memcpy(buffer, holdBuffer, lActualBytes);
  2140.  
  2141.         lAStreamPos += lSrcSamples;
  2142.     } else {
  2143.         len = samples * audioStream->GetFormat()->nBlockAlign;
  2144.         buffer = pipe->getWriteBuffer(len, &handle, INFINITE);
  2145.         if (!buffer) return 0; // aborted
  2146.  
  2147.         destBuffer = (char *)buffer;
  2148.  
  2149.         do {
  2150.             ltActualSamples = audioStream->Read(destBuffer, samples, <ActualBytes);
  2151.  
  2152.             lActualBytes += ltActualBytes;
  2153.             lActualSamples += ltActualSamples;
  2154.  
  2155.             samples -= ltActualSamples;
  2156.             destBuffer += ltActualBytes;
  2157.             len -= ltActualBytes;
  2158.             lAStreamPos += ltActualSamples;
  2159.         } while(samples && ltActualBytes);
  2160.     }
  2161.  
  2162.     pipe->postBuffer(lActualBytes, lActualSamples, -1, handle);
  2163.  
  2164.     aInfo.total_size += lActualBytes + 24;
  2165.     i64SegmentSize += lActualBytes + 24;
  2166.  
  2167.     return lActualBytes;
  2168. }
  2169.  
  2170.  
  2171. //////////////////////
  2172.  
  2173. void Dubber::NextSegment() {
  2174.     char szFile[MAX_PATH];
  2175.     bool fVideo;
  2176.     bool fAudio;
  2177.     AVIOutputFile *AVIout_new;
  2178.  
  2179.     pipe->sync();
  2180.  
  2181.     fVideo = !!AVIout->videoOut;
  2182.     fAudio = !!AVIout->audioOut;
  2183.  
  2184.     ((AVIOutputFile *)AVIout)->setSegmentHintBlock(false, NULL, 1);
  2185.  
  2186.     if (!AVIout->finalize())
  2187.         throw MyError("Error finalizing avi segment");
  2188.  
  2189.     AVIout_new = new AVIOutputFile();
  2190.     if (!AVIout_new)
  2191.         throw MyMemoryError();
  2192.  
  2193.     try {
  2194.         AVIout_new->disable_extended_avi();
  2195.         AVIout_new->disable_os_caching();
  2196.  
  2197.         AVIout_new->setSegmentHintBlock(true, NULL, 1);
  2198.  
  2199.         sprintf(szFile, "%s.%02d.avi", pszSegmentPrefix, nSpillSegment++);
  2200.  
  2201.         if (!AVIout_new->initOutputStreams())
  2202.             throw MyMemoryError();
  2203.  
  2204.         if (fVideo && vSrc) {
  2205.             int l;
  2206.  
  2207.             AVIout_new->videoOut->setCompressed(TRUE);
  2208.             memcpy(&AVIout_new->videoOut->streamInfo, &AVIout->videoOut->streamInfo, sizeof AVIout->videoOut->streamInfo);
  2209.             if (!(AVIout_new->videoOut->allocFormat(l = AVIout->videoOut->getFormatLen())))
  2210.                 throw MyMemoryError();
  2211.  
  2212.             memcpy(AVIout_new->videoOut->getFormat(), AVIout->videoOut->getFormat(), l);
  2213.         }
  2214.         if (fAudio && aSrc) {
  2215.             int l;
  2216.  
  2217.             memcpy(&AVIout_new->audioOut->streamInfo, &AVIout->audioOut->streamInfo, sizeof AVIout->audioOut->streamInfo);
  2218.             if (!(AVIout_new->audioOut->allocFormat(l = AVIout->audioOut->getFormatLen())))
  2219.                 throw MyMemoryError();
  2220.  
  2221.             memcpy(AVIout_new->audioOut->getFormat(), AVIout->audioOut->getFormat(), l);
  2222.         }
  2223.  
  2224.         if (!AVIout_new->init(szFile, 
  2225.                     fVideo ? vSrc ? compressorVideoFormat->bmiHeader.biWidth : 320 : 0, //filters.OutputBitmap()->w,
  2226.                     fVideo ? vSrc ? compressorVideoFormat->bmiHeader.biHeight : 240 : 0, //filters.OutputBitmap()->h,
  2227.                     !!vSrc,
  2228.                     !!aSrc,
  2229.                     opt->perf.outputBufferSize,
  2230.                     opt->audio.enabled))
  2231.             throw MyError("Problem initializing AVI output.");
  2232.     } catch(MyError) {
  2233.         delete AVIout_new;
  2234.         throw;
  2235.     }
  2236.  
  2237.     if (AVIout)
  2238.         delete AVIout;
  2239.  
  2240.     AVIout = AVIout_new;
  2241.  
  2242.     lSegmentFrameStart = lSpillVideoPoint;
  2243.     i64SegmentSize = 0;
  2244.     i64SegmentCredit = 0;
  2245.     lSpillVideoPoint = lSpillAudioPoint = 0;
  2246.     lSpillVideoOk = lSpillAudioOk = 0;
  2247. }
  2248.  
  2249. void Dubber::CheckSpill(long videopt, long audiopt) {
  2250.     long lFrame;
  2251.     long lFrame2;
  2252.     long lSample;
  2253.  
  2254.     // Are the new values still below the last computed 'safe' thresholds?
  2255.  
  2256.     if (videopt <= lSpillVideoOk && audiopt <= lSpillAudioOk)
  2257.         return;
  2258.  
  2259.     // Find out how many sync'ed video frames we'd be pushing ahead.
  2260.  
  2261.     __int64 nAdditionalBytes;
  2262.  
  2263.     lFrame = ((videopt-vInfo.start_src) / opt->video.frameRateDecimation);
  2264.  
  2265.     if (aSrc) {
  2266.         const __int64 nBlockAlignMillion = audioTimingStream->GetFormat()->nBlockAlign * 1000000i64;
  2267.         const __int64 nAvgBytesPerSecSpeed = (__int64)vInfo.usPerFrameNoTelecine * audioTimingStream->GetFormat()->nAvgBytesPerSec;
  2268.  
  2269.         // <audio samples> * <audio bytes per sample> / <audio bytes per second> = <seconds>
  2270.         // <seconds> * 1000000 / <microseconds per frame> = <frames>
  2271.         // (<audio samples> * <audio bytes per sample> * 1000000) / (<audio bytes per second> * <microseconds per frame>) = <frames>
  2272.  
  2273.         lFrame2 = int64divroundup((__int64)(audiopt - aInfo.start_src) * nBlockAlignMillion,
  2274.                     nAvgBytesPerSecSpeed);
  2275.  
  2276.         if (pInvTelecine)
  2277.             lFrame2 += nVideoLag;
  2278.  
  2279.         if (lFrame2 > lFrame)
  2280.             lFrame = lFrame2;
  2281.  
  2282.         // Quantize to 5 frames in inverse telecine mode.
  2283.  
  2284.         lFrame2 = lFrame;
  2285.         if (pInvTelecine) {
  2286.             lFrame += 4;
  2287.             lFrame -= lFrame % 5;
  2288.             lFrame2 = lFrame - 10;
  2289.         }
  2290.  
  2291.         // Find equivalent audio point.
  2292.         //
  2293.         // (<audio samples> = (<frames> * <audio bytes per second> * <microseconds per frame>) / (<audio bytes per sample> * 1000000);
  2294.  
  2295.         lSample = int64divround((__int64)lFrame2 * nAvgBytesPerSecSpeed, nBlockAlignMillion);
  2296.     } else
  2297.         lFrame2 = lFrame;
  2298.  
  2299.     // Figure out how many more bytes it would be.
  2300.  
  2301.     if (opt->video.mode)
  2302.         nAdditionalBytes = (__int64)lVideoSizeEstimate * (vInfo.start_src + lFrame2 * opt->video.frameRateDecimation - vInfo.cur_src + nVideoLag);
  2303.     else {
  2304.         HRESULT hr;
  2305.         LONG lSize = 0;
  2306.         long lSamp = vInfo.cur_src;
  2307.         long lSampLimit = vInfo.start_src + lFrame2 * opt->video.frameRateDecimation + nVideoLag;
  2308.  
  2309.         nAdditionalBytes = 0;
  2310.  
  2311.         while(lSamp < lSampLimit) {
  2312.             hr = vSrc->read(lSamp, 1, NULL, 0x7FFFFFFF, &lSize, NULL);
  2313.             if (!hr)
  2314.                 nAdditionalBytes += lSize;
  2315.             lSamp += opt->video.frameRateDecimation;
  2316.         }
  2317.     }
  2318.  
  2319.     if (aSrc && lSample > aInfo.cur_src)
  2320.         nAdditionalBytes += (lSample - aInfo.cur_src) * audioTimingStream->GetFormat()->nBlockAlign;
  2321.  
  2322.     if (nAdditionalBytes + (i64SegmentSize - i64SegmentCredit) < i64SegmentThreshold && (!lSegmentFrameLimit || lFrame-lSegmentFrameStart<=lSegmentFrameLimit)) {
  2323.  
  2324.         // We're fine.  Mark down the new thresholds so we don't have to recompute them.
  2325.  
  2326.         lFrame = lFrame * opt->video.frameRateDecimation + vInfo.start_src;
  2327.  
  2328.         if (aSrc)
  2329.             lSample += aInfo.start_src;
  2330.  
  2331.         _RPT4(0,"Pushing threshold to %ld, %ld: current position %ld, %ld\n", lFrame, lSample, vInfo.cur_src, aInfo.cur_src);
  2332.  
  2333.         lSpillVideoOk = lFrame;
  2334.  
  2335.         if (aSrc)
  2336.             lSpillAudioOk = lSample;
  2337.  
  2338.         return;
  2339.     }
  2340.  
  2341.     // Doh!  Force a split at the current thresholds.
  2342.  
  2343.     lSpillVideoPoint = lSpillVideoOk;
  2344.  
  2345.     if (aSrc)
  2346.         lSpillAudioPoint = lSpillAudioOk;
  2347.  
  2348.     _RPT4(0,"Forcing split at %ld, %ld: current position %ld, %ld\n", lSpillVideoPoint, lSpillAudioPoint, vInfo.cur_src, aInfo.cur_src);
  2349.  
  2350.     lFrame = lFrame * opt->video.frameRateDecimation + vInfo.start_src;
  2351.     lSpillVideoOk = lFrame;
  2352.  
  2353.     if (aSrc) {
  2354.         lSample += aInfo.start_src;
  2355.         lSpillAudioOk = lSample;
  2356.     }
  2357.  
  2358.     // Are we exactly at the right point?
  2359.  
  2360.     if (vInfo.cur_src == lSpillVideoPoint && (!aSrc || aInfo.cur_src == lSpillAudioPoint))
  2361.         NextSegment();
  2362. }
  2363.  
  2364. void Dubber::MainAddVideoFrame() {
  2365.     long f;
  2366.     BOOL is_preroll;
  2367.  
  2368.     if (vInfo.cur_src < vInfo.end_src + nVideoLag) {
  2369.         BOOL fRead = FALSE;
  2370.         long lFrame = vInfo.cur_src;
  2371.  
  2372.         // If we're doing segment spilling but don't have an audio stream,
  2373.         // break if we can't fit the next frame.
  2374.  
  2375.         if (fEnableSpill && !audioStream)
  2376.             if (i64SegmentSize - i64SegmentCredit >= i64SegmentThreshold)
  2377.                 NextSegment();
  2378.  
  2379.         // If we're using an input subset, translate the frame.
  2380.  
  2381.         if (inputSubsetActive)
  2382.             lFrame = inputSubsetActive->lookupFrame(vInfo.cur_src) + vSrc->lSampleFirst;
  2383.  
  2384.         if (lFrame >= vSrc->lSampleFirst && lFrame < vSrc->lSampleLast) {
  2385.             if (opt->video.mode != DubVideoOptions::M_NONE) {
  2386.                 long lSize;
  2387.                 int nFrames;
  2388.  
  2389.                 vSrc->streamSetDesiredFrame(lFrame);
  2390.  
  2391.                 nFrames = vSrc->streamGetRequiredCount(&lSize);
  2392.  
  2393.                 if (fEnableSpill)
  2394.                     CheckSpill(vInfo.cur_src + opt->video.frameRateDecimation, aInfo.cur_src);
  2395.  
  2396.                 if (!lSpillVideoPoint || vInfo.cur_src < lSpillVideoPoint) {
  2397.                     while(-1 != (f = vSrc->streamGetNextRequiredFrame(&is_preroll))) {
  2398.                         ReadVideoFrame(f, is_preroll && opt->video.mode>=DubVideoOptions::M_FASTREPACK);
  2399.  
  2400.                         fRead = TRUE;
  2401.                     }
  2402.  
  2403.                     if (!fRead) ReadNullVideoFrame(lFrame);
  2404.                 }
  2405.             } else {
  2406.  
  2407.                 if (fEnableSpill)
  2408.                     CheckSpill(vInfo.cur_src + opt->video.frameRateDecimation, aInfo.cur_src);
  2409.  
  2410.                 if (!lSpillVideoPoint || vInfo.cur_src < lSpillVideoPoint)
  2411.                     ReadVideoFrame(lFrame, FALSE);
  2412.             }
  2413.         } else {
  2414.             // Flushing out the lag -- read a null frame.
  2415.  
  2416.             ReadNullVideoFrame(lFrame);
  2417.         }
  2418.     }
  2419.  
  2420.     vInfo.cur_src += opt->video.frameRateDecimation;
  2421. }
  2422.  
  2423. void Dubber::MainAddAudioFrame(int lag) {
  2424.     long lAvgBytesPerSec = audioTimingStream->GetFormat()->nAvgBytesPerSec;
  2425.     long lBlockSize;
  2426.     LONG lAudioPoint;
  2427.     LONG lFrame = ((vInfo.cur_src-vInfo.start_src-lag) / opt->video.frameRateDecimation);
  2428.  
  2429.     // Per-frame interleaving?
  2430.  
  2431.     if (!opt->audio.is_ms || opt->audio.interval<=1) {
  2432.         if (opt->audio.interval > 1)
  2433.             lFrame = ((lFrame+opt->audio.interval-1)/opt->audio.interval)*opt->audio.interval;
  2434.  
  2435.         lAudioPoint = (long)(aInfo.start_src + aInfo.lPreloadSamples +
  2436.             (
  2437.                 ((__int64)lAvgBytesPerSec*(__int64)vInfo.usPerFrameNoTelecine*lFrame)
  2438.                 /
  2439.                 ((__int64)1000000*audioTimingStream->GetFormat()->nBlockAlign)
  2440.             ));
  2441.  
  2442.     } else {                        // Per n-ms interleaving
  2443.  
  2444.         __int64 i64CurrentFrameMs;
  2445.  
  2446.         i64CurrentFrameMs = ((__int64)vInfo.usPerFrameNoTelecine * lFrame)/1000;
  2447.  
  2448.         // Round up lCurrentFrameMs to next interval
  2449.  
  2450.         i64CurrentFrameMs = ((i64CurrentFrameMs+opt->audio.interval-1)/opt->audio.interval)*opt->audio.interval;
  2451.  
  2452.         // nAvgBytesPerSec/nBlockAlign = samples per second
  2453.  
  2454.         lAudioPoint = aInfo.start_src + aInfo.lPreloadSamples +
  2455.                 (LONG)((i64CurrentFrameMs * lAvgBytesPerSec) / (audioTimingStream->GetFormat()->nBlockAlign*1000));
  2456.  
  2457.     }
  2458.  
  2459.     // Round lAudioPoint to next block size if preview
  2460.  
  2461.     if (fPreview) {
  2462.         lBlockSize = (lAvgBytesPerSec / audioTimingStream->GetFormat()->nBlockAlign+4)/5;
  2463.  
  2464.         lAudioPoint += lBlockSize - 1;
  2465.         lAudioPoint -= lAudioPoint % lBlockSize;
  2466.     }
  2467.  
  2468.     if (lAudioPoint <= aInfo.cur_src)
  2469.         return;
  2470.  
  2471.     if (fEnableSpill)
  2472.         CheckSpill(vInfo.cur_src, lAudioPoint);
  2473.  
  2474.     if (lSpillAudioPoint && lAudioPoint > lSpillAudioPoint)
  2475.         lAudioPoint = lSpillAudioPoint;
  2476.  
  2477.     if (lAudioPoint > aInfo.cur_src)
  2478.         ReadAudio(aInfo.cur_src,lAudioPoint - aInfo.cur_src);
  2479.  
  2480.     _ASSERT(aInfo.cur_src <= lAudioPoint);
  2481. }
  2482.  
  2483. void Dubber::MainThreadKickstart(void *thisPtr) {
  2484.     InitThreadData("I/O processing");
  2485.     ((Dubber *)thisPtr)->MainThread();
  2486.     DeinitThreadData();
  2487. }
  2488.  
  2489. void Dubber::MainThread() {
  2490.  
  2491.     ///////////
  2492.  
  2493.     _XRPT0(0,"Dub/Main: Start.\n");
  2494.  
  2495.     InterlockedIncrement((LONG *)&lThreadsActive);
  2496.  
  2497.     try {
  2498.  
  2499.         DEFINE_SP(sp);
  2500.  
  2501.         // Preload audio before the first video frame.
  2502.  
  2503. //        _RPT1(0,"Before preload: %ld\n", aInfo.cur_src);
  2504.  
  2505.         if (aSrc) {
  2506.             aInfo.lPreloadSamples    = (long)(((__int64)opt->audio.preload * audioTimingStream->GetFormat()->nAvgBytesPerSec)/(1000 * audioTimingStream->GetFormat()->nBlockAlign));
  2507.  
  2508.             if (aInfo.lPreloadSamples>0) {
  2509.                 _RPT1(0,"Dub/Main: Prewriting %ld samples\n", aInfo.lPreloadSamples);
  2510.                 ReadAudio(aInfo.cur_src, aInfo.lPreloadSamples);
  2511.             }
  2512.         }
  2513.  
  2514. //        _RPT1(0,"After preload: %ld\n", aInfo.cur_src);
  2515.  
  2516.         // Do it!!!
  2517.  
  2518.         try {
  2519.             if (opt->audio.enabled && aSrc && vSrc && AVIout->videoOut) {
  2520.                 LONG lStreamCounter = 0;
  2521.  
  2522.                 _RPT0(0,"Dub/Main: Taking the **Interleaved** path.\n");
  2523.  
  2524.                 while(!fAbort && (vInfo.cur_src<vInfo.end_src+nVideoLag || !audioStream->isEnd())) { 
  2525.                     BOOL doAudio = TRUE;
  2526.  
  2527.                     CHECK_STACK(sp);
  2528.  
  2529.                     if (!lSpillVideoPoint || vInfo.cur_src < lSpillVideoPoint)
  2530.                         MainAddVideoFrame();
  2531.  
  2532.                     if ((!lSpillAudioPoint || aInfo.cur_src < lSpillAudioPoint) && audioStream && !audioStream->isEnd()) {
  2533.                         MainAddAudioFrame(nVideoLag);
  2534.                     }
  2535.  
  2536.                     if (lSpillVideoPoint && vInfo.cur_src == lSpillVideoPoint && aInfo.cur_src == lSpillAudioPoint)
  2537.                         NextSegment();
  2538.  
  2539. //                    _RPT3(0,"segment size: %I64d - %I64d = %I64d\n", i64SegmentSize, i64SegmentCredit, i64SegmentSize - i64SegmentCredit);
  2540.                 }
  2541.  
  2542.             } else {
  2543.                 _RPT0(0,"Dub/Main: Taking the **Non-Interleaved** path.\n");
  2544.  
  2545.                 if (aSrc)
  2546.                     while(!fAbort && !audioStream->isEnd()) {
  2547.                         ReadAudio(aInfo.cur_src, 1024); //8192);
  2548.                     }
  2549.  
  2550.                 if (vSrc && AVIout->videoOut)
  2551.                     while(!fAbort && vInfo.cur_src < vInfo.end_src) { 
  2552.                         BOOL fRead = FALSE;
  2553.                         long lFrame = vInfo.cur_src;
  2554.  
  2555.                         CHECK_STACK(sp);
  2556.  
  2557.                         if (!lSpillVideoPoint || vInfo.cur_src < lSpillVideoPoint)
  2558.                             MainAddVideoFrame();
  2559.  
  2560.                         if (lSpillVideoPoint && vInfo.cur_src == lSpillVideoPoint)
  2561.                             NextSegment();
  2562.  
  2563.                     }
  2564.             }
  2565.         } catch(MyError e) {
  2566.             e.post(NULL, "Dub Error (will attempt to finalize)");
  2567.         }
  2568.  
  2569.         // wait for the pipeline to clear...
  2570.  
  2571.         if (!fAbort) pipe->finalize();
  2572.  
  2573.         // finalize the output.. if it's not a preview...
  2574.  
  2575.         if (!AVIout->isPreview()) {
  2576.             while(lThreadsActive>1) {
  2577. //            _RPT1(0,"\tDub/Main: %ld threads active\n", lThreadsActive);
  2578.  
  2579.                 WaitForSingleObject(hEventAbortOk, 200);
  2580.             }
  2581.  
  2582.             _RPT0(0,"Dub/Main: finalizing...\n");
  2583.  
  2584.             // update audio rate...
  2585.  
  2586.             if (audioCorrector) {
  2587.                 WAVEFORMATEX *wfex = AVIout->audioOut->getWaveFormat();
  2588.                 
  2589.                 wfex->nAvgBytesPerSec = audioCorrector->ComputeByterate(wfex->nSamplesPerSec);
  2590.  
  2591.                 AVIout->audioOut->streamInfo.dwRate = wfex->nAvgBytesPerSec
  2592.                     * AVIout->audioOut->streamInfo.dwScale;
  2593.             }
  2594.  
  2595.             // finalize avi
  2596.  
  2597.             if (!AVIout->finalize()) throw MyError("Error finalizing AVI!");
  2598.             _RPT0(0,"Dub/Main: finalized.\n");
  2599.         }
  2600.  
  2601.         // kill everyone else...
  2602.  
  2603.         fAbort = true;
  2604.  
  2605.     } catch(MyError e) {
  2606. //        e.post(NULL,"Dub Error");
  2607.  
  2608.         if (!fError) {
  2609.             err = e;
  2610.             e.discard();
  2611.             fError = true;
  2612.         }
  2613.         fAbort = TRUE;
  2614.     } catch(int) {
  2615.         ;    // do nothing
  2616.     }
  2617.  
  2618.     // All done, time to get the pooper-scooper and clean up...
  2619.  
  2620.     hThreadMain = NULL;
  2621.  
  2622.     InterlockedDecrement((LONG *)&lThreadsActive);
  2623.     SetEvent(hEventAbortOk);
  2624.  
  2625. #ifdef _DEBUG
  2626.     _CrtCheckMemory();
  2627. #endif
  2628.  
  2629.     _XRPT0(0,"Dub/Main: End.\n");
  2630. }
  2631.  
  2632. ///////////////////////////////////////////////////////////////////
  2633.  
  2634. #define BUFFERID_INPUT (1)
  2635. #define BUFFERID_OUTPUT (2)
  2636. #define BUFFERID_PACKED (4)
  2637.  
  2638. void Dubber::WriteVideoFrame(void *buffer, int exdata, LONG lastSize, long sample_num) {
  2639.     LONG dwBytes;
  2640.     bool isKey;
  2641.     void *frameBuffer;
  2642.     LPVOID lpCompressedData;
  2643.  
  2644.     // With Direct mode, write video data directly to output.
  2645.  
  2646.     if (opt->video.mode == DubVideoOptions::M_NONE || fPhantom) {
  2647.  
  2648. //        _RPT2(0,"Processing frame %ld (#%ld)\n", sample_num, vInfo.cur_proc_src+1);
  2649.  
  2650.         if (!AVIout->videoOut->write((exdata & 1) ? 0 : AVIIF_KEYFRAME, (char *)buffer, lastSize, 1))
  2651.             throw MyError("Error writing video frame.");
  2652.  
  2653.         vInfo.total_size += lastSize + 24;
  2654.         ++vInfo.cur_proc_src;
  2655.         ++vInfo.processed;
  2656.  
  2657.         pStatusHandler->NotifyNewFrame(lastSize | (exdata&1 ? 0x80000000 : 0));
  2658.  
  2659.         return;
  2660.     }
  2661.  
  2662.     // Fast Repack: Decompress data and send to compressor (possibly non-RGB).
  2663.     // Slow Repack: Decompress data and send to compressor.
  2664.     // Full:        Decompress, process, filter, convert, send to compressor.
  2665.  
  2666.     blitter->lock(BUFFERID_INPUT);
  2667.  
  2668. //    _RPT2(0,"Sample %ld (keyframe: %d)\n", sample_num, !(exdata &1));
  2669.  
  2670.     VDCHECKPOINT;
  2671.     CHECK_FPU_STACK
  2672.     vSrc->streamGetFrame(buffer, lastSize, !(exdata&1), FALSE, sample_num);
  2673.     CHECK_FPU_STACK
  2674.     VDCHECKPOINT;
  2675.  
  2676. //    guiSetStatus("Pulse clock: %ld, Delta: %ld\n", g_lPulseClock, blitter->getFrameDelta());
  2677.  
  2678.     if (exdata & 2) {
  2679.         blitter->unlock(BUFFERID_INPUT);
  2680. //        ++vInfo.cur_proc_src;
  2681.         return;
  2682.     }
  2683.  
  2684.     if (lDropFrames && fPreview) {
  2685.         blitter->unlock(BUFFERID_INPUT);
  2686.         blitter->nextFrame();
  2687.         vInfo.cur_proc_src += opt->video.frameRateDecimation;
  2688.         ++fsi.lCurrentFrame;
  2689.         --lDropFrames;
  2690.  
  2691.         pStatusHandler->NotifyNewFrame(0);
  2692.  
  2693.         return;
  2694.     }
  2695.  
  2696.     // Process frame to backbuffer for Full video mode.  Do not process if we are
  2697.     // running in Repack mode only!
  2698.     if (opt->video.mode == DubVideoOptions::M_FULL) {
  2699.         VBitmap *initialBitmap = filters.InputBitmap();
  2700.         VBitmap *lastBitmap = filters.LastBitmap();
  2701.         VBitmap *outputBitmap = filters.OutputBitmap();
  2702.         VBitmap destbm;
  2703.         long lInputFrameNum, lInputFrameNum2;
  2704.  
  2705.         lInputFrameNum = sample_num - vSrc->lSampleFirst;
  2706.  
  2707.         if (pInvTelecine) {
  2708.             lInputFrameNum2 = pInvTelecine->ProcessOut(initialBitmap);
  2709.             pInvTelecine->ProcessIn(&VBitmap(vSrc->getFrameBuffer(), vSrc->getDecompressedFormat()), lInputFrameNum);
  2710.  
  2711.             lInputFrameNum = lInputFrameNum2;
  2712.  
  2713.             if (lInputFrameNum < 0) {
  2714.                 blitter->unlock(BUFFERID_INPUT);
  2715.                 vInfo.cur_proc_src += opt->video.frameRateDecimation;
  2716.                 return;
  2717.             }
  2718.         } else
  2719.             initialBitmap->BitBlt(0, 0, &VBitmap(vSrc->getFrameBuffer(), vSrc->getDecompressedFormat()), 0, 0, -1, -1);
  2720.  
  2721.  
  2722.         if (inputHisto) {
  2723.             inputHisto->Zero();
  2724.             inputHisto->Process(filters.InputBitmap());
  2725.         }
  2726.  
  2727.         // process frame
  2728.  
  2729. //        fsi.lCurrentFrame        = (sample_num - vInfo.start_src) / opt->video.frameRateDecimation;
  2730.  
  2731.         fsi.lCurrentSourceFrame    = lInputFrameNum;
  2732.         fsi.lSourceFrameMS        = MulDiv(fsi.lCurrentSourceFrame, fsi.lMicrosecsPerSrcFrame, 1000);
  2733.         fsi.lDestFrameMS        = MulDiv(fsi.lCurrentFrame, fsi.lMicrosecsPerFrame, 1000);
  2734.  
  2735.         CHECK_FPU_STACK
  2736.  
  2737.         filters.RunFilters();
  2738.  
  2739.         CHECK_FPU_STACK
  2740.  
  2741.         ++fsi.lCurrentFrame;
  2742.  
  2743.         if (nVideoLagPreload>0) {
  2744.             --nVideoLagPreload;
  2745.             blitter->unlock(BUFFERID_INPUT);
  2746.             vInfo.cur_proc_src += opt->video.frameRateDecimation;
  2747.             return;
  2748.         }
  2749.  
  2750.  
  2751.         blitter->lock(BUFFERID_OUTPUT);
  2752.  
  2753. //        if (!outputDecompressor)
  2754. //            outputBitmap.data = outputBuffer;
  2755.  
  2756.         do {
  2757.             if (pdsOutput) {
  2758.                 if (!pdsOutput->LockInverted(&destbm))
  2759.                     break;
  2760.  
  2761.                 outputBitmap = &destbm;
  2762.             }
  2763.  
  2764.             if (fPreview && g_prefs.fDisplay & Preferences::DISPF_DITHER16)
  2765.                 outputBitmap->BitBltDither(0, 0, lastBitmap, 0, 0, -1, -1, fDisplay565);
  2766.             else if (bihDisplayFormat.bV4V4Compression == BI_BITFIELDS)
  2767.                 outputBitmap->BitBlt565(0, 0, lastBitmap, 0, 0, -1, -1);
  2768.             else
  2769.                 outputBitmap->BitBlt(0, 0, lastBitmap, 0, 0, -1, -1);
  2770.  
  2771.             if (pdsOutput)
  2772.                 pdsOutput->Unlock();
  2773.  
  2774.         } while(false);
  2775.     }
  2776.  
  2777.     // write it to the file
  2778.     
  2779.     frameBuffer =         /*(opt->video.mode == DubVideoOptions::M_FASTREPACK ? buffer : */
  2780.                         opt->video.mode <= DubVideoOptions::M_SLOWREPACK ? vSrc->getFrameBuffer()
  2781.                         :filters.OutputBitmap()->data;
  2782.  
  2783.  
  2784.     if (fUseVideoCompression) {
  2785. /*        if (!(lpCompressedData = ICSeqCompressFrame(compVars, 0, frameBuffer, 
  2786.                         &isKey, &dwBytes)))
  2787.             throw MyError("Error compressing video data.");*/
  2788.  
  2789.         if (hicOutput)
  2790.             blitter->lock(BUFFERID_PACKED);
  2791.  
  2792.         CHECK_FPU_STACK
  2793.         lpCompressedData = pVideoPacker->packFrame(frameBuffer, &isKey, &dwBytes);
  2794.         CHECK_FPU_STACK
  2795.  
  2796.         if (fShowDecompressedFrame && outputDecompressor && dwBytes) {
  2797.             DWORD err;
  2798.             VBitmap *outputBitmap = filters.OutputBitmap();
  2799.             Pixel *outputBuffer = outputBitmap->data;
  2800.  
  2801. //            memset(outputBuffer, 0, outputBitmap->size);
  2802.  
  2803.             CHECK_FPU_STACK
  2804.  
  2805.             DWORD dwSize = compressorVideoFormat->bmiHeader.biSizeImage;
  2806.  
  2807.             compressorVideoFormat->bmiHeader.biSizeImage = dwBytes;
  2808.  
  2809.             VDCHECKPOINT;
  2810.             if (ICERR_OK != (err = ICDecompress(outputDecompressor,
  2811.                 isKey ? 0 : ICDECOMPRESS_NOTKEYFRAME,
  2812.                 AVIout->videoOut->getImageFormat(),
  2813.                 lpCompressedData,
  2814.                 &compressorVideoFormat->bmiHeader,
  2815.                 outputBuffer
  2816.                 )))
  2817.  
  2818. //                    throw "Error decompressing output video frame.\n";
  2819. //                    throw MyICError("Dub/Processor-Video (output)", err);
  2820.  
  2821.                 fShowDecompressedFrame = false;
  2822.             VDCHECKPOINT;
  2823.  
  2824.             compressorVideoFormat->bmiHeader.biSizeImage = dwSize;
  2825.  
  2826.             CHECK_FPU_STACK
  2827.         }
  2828.  
  2829.         if (!AVIout->videoOut->write(isKey ? AVIIF_KEYFRAME : 0, (char *)lpCompressedData, dwBytes, 1))
  2830.             throw "Error writing video frame.";
  2831.  
  2832.     } else {
  2833.  
  2834. /*        if (!AVIout->videoOut->write(AVIIF_KEYFRAME, (char *)frameBuffer, filters.OutputBitmap()->size, 1))
  2835.             throw MyError("Error writing video frame.");
  2836.  
  2837.         dwBytes = filters.OutputBitmap()->size;*/
  2838.  
  2839.         VDCHECKPOINT;
  2840.         if (!AVIout->videoOut->write(AVIIF_KEYFRAME, (char *)frameBuffer, AVIout->videoOut->getImageFormat()->biSizeImage, 1))
  2841.             throw MyError("Error writing video frame.");
  2842.         VDCHECKPOINT;
  2843.  
  2844.         dwBytes = AVIout->videoOut->getImageFormat()->biSizeImage;
  2845.         isKey = true;
  2846.     }
  2847.  
  2848.     vInfo.total_size += dwBytes + 24;
  2849.  
  2850.     VDCHECKPOINT;
  2851.  
  2852.     if (okToDraw || fPreview) {
  2853.         if (opt->video.fShowInputFrame) {
  2854.             if (inputHisto) {
  2855.                 inputHisto->Draw(hDCWindow, &rInputHistogram);
  2856.             }
  2857.  
  2858.             if (pdsInput) {
  2859.                 if (opt->video.nPreviewFieldMode)
  2860.                     blitter->postDirectDrawCopyLaced(
  2861.                             BUFFERID_INPUT,
  2862.                             vSrc->getFrameBuffer(),
  2863.                             vSrc->getDecompressedFormat(),
  2864.                             pdsInput,
  2865.                             opt->video.nPreviewFieldMode>=2
  2866.                     );
  2867.                 else
  2868.                     blitter->postDirectDrawCopy(
  2869.                             BUFFERID_INPUT,
  2870.                             vSrc->getFrameBuffer(),
  2871.                             vSrc->getDecompressedFormat(),
  2872.                             pdsInput
  2873.                     );
  2874.             } else if (hbmInput) {
  2875.                 if (opt->video.nPreviewFieldMode)
  2876.                     blitter->postBitBltLaced(
  2877.                             BUFFERID_INPUT,
  2878.                             hDCWindow,
  2879.                             rInputFrame.left, rInputFrame.top,
  2880.                             rInputFrame.right-rInputFrame.left, rInputFrame.bottom-rInputFrame.top,
  2881.                             hdcCompatInput,
  2882.                             0,0,
  2883.                             opt->video.nPreviewFieldMode>=2
  2884.                     );
  2885.                 else
  2886.                     blitter->postStretchBlt(
  2887.                             BUFFERID_INPUT,
  2888.                             hDCWindow,
  2889.                             rInputFrame.left, rInputFrame.top,
  2890.                             rInputFrame.right-rInputFrame.left, rInputFrame.bottom-rInputFrame.top,
  2891.                             hdcCompatInput,
  2892.                             0,0,
  2893.                             vSrc->getDecompressedFormat()->biWidth,vSrc->getDecompressedFormat()->biHeight
  2894.                     );
  2895.             } else if (hDDInput)
  2896.                 blitter->post(
  2897.                         BUFFERID_INPUT,
  2898.                         hDDInput,
  2899.                         hDCWindow,
  2900.                         rInputFrame.left, rInputFrame.top,
  2901.                         rInputFrame.right-rInputFrame.left, rInputFrame.bottom-rInputFrame.top,
  2902.                         vSrc->getDecompressedFormat(),
  2903.                         vSrc->getFrameBuffer(),
  2904.                         0,0,
  2905.                         vSrc->getDecompressedFormat()->biWidth,vSrc->getDecompressedFormat()->biHeight,
  2906.                         DDF_SAME_HDC | DDF_SAME_DRAW
  2907.                     );
  2908.             else if (g_fWine)
  2909.                 blitter->postStretchDIBits(
  2910.                         BUFFERID_INPUT,
  2911.                         hDCWindow,
  2912.                         rInputFrame.left, rInputFrame.top,
  2913.                         rInputFrame.right-rInputFrame.left, rInputFrame.bottom-rInputFrame.top,
  2914.                         0,0,
  2915.                         vSrc->getDecompressedFormat()->biWidth,vSrc->getDecompressedFormat()->biHeight,
  2916.                         vSrc->getFrameBuffer(),
  2917.                         (LPBITMAPINFO)vSrc->getDecompressedFormat(),
  2918.                         DIB_RGB_COLORS,
  2919.                         SRCCOPY
  2920.                     );
  2921.             else
  2922.                 blitter->unlock(BUFFERID_INPUT);
  2923.         } else
  2924.             blitter->unlock(BUFFERID_INPUT);
  2925.  
  2926.         if (hicOutput && lpCompressedData)
  2927.             blitter->postICDraw(BUFFERID_PACKED, hicOutput, isKey ? 0 : ICDRAW_NOTKEYFRAME, AVIout->videoOut->getImageFormat(), lpCompressedData, dwBytes, vInfo.processed);
  2928.  
  2929.         if (opt->video.mode == DubVideoOptions::M_FULL && opt->video.fShowOutputFrame && (!outputDecompressor || dwBytes)) {
  2930.             if (outputHisto) {
  2931.                 outputHisto->Zero();
  2932.                 outputHisto->Process(filters.LastBitmap());
  2933.  
  2934.                 outputHisto->Draw(hDCWindow, &rOutputHistogram);
  2935.             }
  2936.  
  2937.             if (pdsOutput) {
  2938.                 if (opt->video.nPreviewFieldMode)
  2939.                     blitter->postDirectDrawBlitLaced(
  2940.                             BUFFERID_OUTPUT,
  2941.                             DDrawObtainPrimary(),
  2942.                             pdsOutput,
  2943.                             rOutputFrame.left+x_client, rOutputFrame.top+y_client,
  2944.                             rOutputFrame.right-rOutputFrame.left, rOutputFrame.bottom-rOutputFrame.top,
  2945.                             opt->video.nPreviewFieldMode>=2
  2946.                             );
  2947.                 else
  2948.                     blitter->postDirectDrawBlit(
  2949.                             BUFFERID_OUTPUT,
  2950.                             DDrawObtainPrimary(),
  2951.                             pdsOutput,
  2952.                             rOutputFrame.left+x_client, rOutputFrame.top+y_client,
  2953.                             rOutputFrame.right-rOutputFrame.left, rOutputFrame.bottom-rOutputFrame.top);
  2954.             } else if (hbmOutput) {
  2955.                 if (opt->video.nPreviewFieldMode)
  2956.                     blitter->postBitBltLaced(
  2957.                             BUFFERID_OUTPUT,
  2958.                             hDCWindow,
  2959.                             rOutputFrame.left, rOutputFrame.top,
  2960.                             rOutputFrame.right-rOutputFrame.left, rOutputFrame.bottom-rOutputFrame.top,
  2961.                             hdcCompatOutput,
  2962.                             0,0,
  2963.                             opt->video.nPreviewFieldMode>=2
  2964.                     );
  2965.                 else
  2966.                     blitter->postStretchBlt(
  2967.                             BUFFERID_OUTPUT,
  2968.                             hDCWindow,
  2969.                             rOutputFrame.left, rOutputFrame.top,
  2970.                             rOutputFrame.right-rOutputFrame.left, rOutputFrame.bottom-rOutputFrame.top,
  2971.                             hdcCompatOutput,
  2972.                             0,0,
  2973.                             filters.OutputBitmap()->w,
  2974.                             filters.OutputBitmap()->h
  2975.                     );
  2976.             } else if (hDDOutput)
  2977.                 blitter->post(
  2978.                         BUFFERID_OUTPUT,
  2979.                         hDDOutput,
  2980.                         hDCWindow,
  2981.                         rOutputFrame.left, rOutputFrame.top,
  2982.                         rOutputFrame.right-rOutputFrame.left, rOutputFrame.bottom-rOutputFrame.top,
  2983.                         &compressorVideoFormat->bmiHeader,
  2984.                         filters.OutputBitmap()->data, //outputBuffer,
  2985.                         0,0,
  2986.                         filters.OutputBitmap()->w,
  2987.                         filters.OutputBitmap()->h,
  2988.                         DDF_SAME_HDC | DDF_SAME_DRAW
  2989.                 );
  2990.             else if (g_fWine)
  2991.                 blitter->postStretchDIBits(
  2992.                         BUFFERID_OUTPUT,
  2993.                         hDCWindow,
  2994.                         rOutputFrame.left, rOutputFrame.top,
  2995.                         rOutputFrame.right-rOutputFrame.left, rOutputFrame.bottom-rOutputFrame.top,
  2996.                         0,0,
  2997.                         filters.OutputBitmap()->w,
  2998.                         filters.OutputBitmap()->h,
  2999.                         filters.OutputBitmap()->data, //outputBuffer,
  3000.                         (LPBITMAPINFO)&compressorVideoFormat->bmiHeader,
  3001.                         DIB_RGB_COLORS,
  3002.                         SRCCOPY
  3003.                     );
  3004.             else
  3005.                 blitter->unlock(BUFFERID_OUTPUT);
  3006.  
  3007.         } else
  3008.             blitter->unlock(BUFFERID_OUTPUT);
  3009.  
  3010.         --okToDraw;
  3011.     } else {
  3012.         blitter->unlock(BUFFERID_OUTPUT);
  3013.         blitter->unlock(BUFFERID_INPUT);
  3014.         blitter->unlock(BUFFERID_PACKED);
  3015.     }
  3016.  
  3017. //    guiSetStatus("Pulse clock: %ld\n", g_lPulseClock);
  3018.  
  3019.     if (opt->perf.fDropFrames && fPreview) {
  3020.         long lFrameDelta;
  3021.  
  3022.         lFrameDelta = blitter->getFrameDelta();
  3023.  
  3024.         if (opt->video.nPreviewFieldMode)
  3025.             lFrameDelta >>= 1;
  3026.  
  3027. //        guiSetStatus("Pulse clock: %ld, Delta: %ld\n", g_lPulseClock, lFrameDelta);
  3028.  
  3029.         if (lFrameDelta < 1) lFrameDelta = 1;
  3030.         
  3031.         if (lFrameDelta > 1) {
  3032.             lDropFrames = lFrameDelta/2;
  3033.         }
  3034.  
  3035. //        vInfo.cur_proc_src = opt->video.frameRateDecimation * lFrameDelta;
  3036.     }
  3037.  
  3038.     blitter->nextFrame(opt->video.nPreviewFieldMode ? 2 : 1);
  3039.  
  3040.     vInfo.cur_proc_src += opt->video.frameRateDecimation;
  3041.     ++vInfo.processed;
  3042.  
  3043.     if (opt->video.mode)
  3044.         i64SegmentCredit += lVideoSizeEstimate - (dwBytes + (dwBytes&1));
  3045.  
  3046.     pStatusHandler->NotifyNewFrame(isKey ? dwBytes : dwBytes | 0x80000000);
  3047.  
  3048.     VDCHECKPOINT;
  3049.  
  3050. }
  3051.  
  3052. void Dubber::WriteAudio(void *buffer, long lActualBytes, long lActualSamples) {
  3053.     if (!lActualBytes) return;
  3054.  
  3055.     if (!AVIout->audioOut->write(AVIIF_KEYFRAME, (char *)buffer, lActualBytes, lActualSamples))
  3056.         throw MyError("Error writing audio data.");
  3057.  
  3058.     aInfo.cur_proc_src += lActualBytes;
  3059. }
  3060.  
  3061. void Dubber::ProcessingThreadKickstart(void *thisPtr) {
  3062.     InitThreadData("Processing");
  3063.     ((Dubber *)thisPtr)->ProcessingThread();
  3064.     DeinitThreadData();
  3065. }
  3066.  
  3067. void Dubber::ProcessingThread() {
  3068.     BOOL quit = FALSE;
  3069.     BOOL firstPacket = TRUE;
  3070.     BOOL stillAudio = TRUE;
  3071.  
  3072.     lDropFrames = 0;
  3073.     vInfo.processed = 0;
  3074.  
  3075.     _RPT0(0,"Dub/Processor: start\n");
  3076.  
  3077.     InterlockedIncrement((LONG *)&lThreadsActive);
  3078.  
  3079.     try {
  3080.         DEFINE_SP(sp);
  3081.  
  3082.         do {
  3083.             void *buf;
  3084.             long len;
  3085.             long samples;
  3086.             int exdata;
  3087.             int handle;
  3088.  
  3089.             while(!fAbort && (buf = pipe->getReadBuffer(&len, &samples, &exdata, &handle, 1000))) {
  3090.  
  3091.                 CHECK_STACK(sp);
  3092.  
  3093.                 if (exdata<0) {
  3094.                     WriteAudio(buf, len, samples);
  3095.                     if (firstPacket && fPreview) {
  3096.                         AVIout->audioOut->flush();
  3097.                         blitter->enablePulsing(TRUE);
  3098.                         firstPacket = FALSE;
  3099.  
  3100.                         if (hicOutput)
  3101.                             ICDrawStart(hicOutput);
  3102.                     }
  3103.  
  3104.                 } else {
  3105.                     if (firstPacket && fPreview && !aSrc) {
  3106.                         blitter->enablePulsing(TRUE);
  3107.                         firstPacket = FALSE;
  3108.                     }
  3109.                     WriteVideoFrame(buf, exdata, len, samples);
  3110.                 }
  3111.                 pipe->releaseBuffer(handle);
  3112.  
  3113.                 if (stillAudio && pipe->isNoMoreAudio()) {
  3114.                     // HACK!! if it's a preview, flush the audio
  3115.  
  3116.                     if (AVIout->isPreview()) {
  3117.                         _RPT0(0,"Dub/Processor: flushing audio...\n");
  3118.                         AVIout->audioOut->flush();
  3119.                         _RPT0(0,"Dub/Processor: flushing audio....\n");
  3120.                     }
  3121.  
  3122.                     stillAudio = FALSE;
  3123.                 }
  3124.  
  3125.             }
  3126.         } while(!fAbort && !pipe->isFinalized());
  3127.     } catch(MyError e) {
  3128.         if (!fError) {
  3129.             err = e;
  3130.             e.discard();
  3131.             fError = true;
  3132.         }
  3133.         pipe->abort();
  3134.         fAbort = TRUE;
  3135.     }
  3136.  
  3137.     pipe->isFinalized();
  3138.  
  3139.     // if preview mode, choke the audio
  3140.  
  3141.     if (AVIout->audioOut && AVIout->isPreview())
  3142.         ((AVIAudioPreviewOutputStream *)AVIout->audioOut)->stop();
  3143.  
  3144.     _XRPT0(0,"Dub/Processor: end\n");
  3145.  
  3146.     hThreadProcessor = NULL;
  3147.  
  3148.     InterlockedDecrement((LONG *)&lThreadsActive);
  3149.     SetEvent(hEventAbortOk);
  3150. }
  3151.  
  3152. ///////////////////////////////////////////////////////////////////
  3153.  
  3154. void Dubber::Abort() {
  3155. #ifdef STOP_SPEED_DEBUGGING
  3156.     __asm {
  3157.         rdtsc
  3158.         mov dword ptr start_time+0,eax
  3159.         mov dword ptr start_time+4,edx
  3160.     }
  3161. #endif
  3162.  
  3163.     fUserAbort = true;
  3164.     fAbort = true;
  3165.     PostMessage(g_hWnd, WM_USER, 0, 0);
  3166. }
  3167.  
  3168. bool Dubber::isAbortedByUser() {
  3169.     return fUserAbort;
  3170. }
  3171.  
  3172. void Dubber::Tag(int x, int y) {
  3173.     POINT p;
  3174.  
  3175.     p.x = x;
  3176.     p.y = y;
  3177.  
  3178.     if (PtInRect(&rInputFrame, p))
  3179.         opt->video.fShowInputFrame = !opt->video.fShowInputFrame;
  3180.     else if (PtInRect(&rOutputFrame, p))
  3181.         opt->video.fShowOutputFrame = !opt->video.fShowOutputFrame;
  3182.     else if (PtInRect(&rInputHistogram, p)) {
  3183.         if (inputHisto) inputHisto->SetMode(Histogram::MODE_NEXT);
  3184.     } else if (PtInRect(&rOutputHistogram, p)) {
  3185.         if (outputHisto) outputHisto->SetMode(Histogram::MODE_NEXT);
  3186.     }
  3187. }
  3188.  
  3189. void Dubber::RealizePalette() {
  3190.     if (hDDOutput)
  3191.         DrawDibRealize(hDDOutput, hDCWindow, FALSE);
  3192. }
  3193.  
  3194. void Dubber::SetPriority(int index) {
  3195.     SetThreadPriority(hThreadMain, g_iPriorities[index][0]);
  3196.     SetThreadPriority(hThreadProcessor, g_iPriorities[index][1]);
  3197. }
  3198.  
  3199. void Dubber::UpdateFrames() {
  3200.     ++okToDraw;
  3201. }